2009-08-01 4 views
5

В моем приложении есть основной поток и рабочий поток (QThread).
Из основного потока я бы хотел вызвать метод моего рабочего потока и запустить его в контексте потока.Вызов методов в контексте QThread

Я пробовал использовать QMetaObject::invokeMethod и дать ему QueuedConnection вариант, но он не работает.
Я также пытался испускать сигналы из основного потока (который подключен к слоту рабочего потока), но это также не удалось.

Вот фрагмент примерно то, что я пробовал:

class Worker : public QThread 
{ 
    Q_OBJECT 

public: 
    Worker() { } 

    void run() 
    { 
     qDebug() << "new thread id " << QThread::currentThreadId(); 
     exec(); 
    } 

public slots: 
    void doWork() 
    { 
     qDebug() << "executing thread id - " << QThread::currentThreadId(); 
    } 
}; 

Используя способ QMetaObject:

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    qDebug() << "main thread id - " << QThread::currentThreadId(); 

    Worker worker; 
    worker.start(); 

    QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection); 

    return a.exec(); 
} 

Используя путь сигнала:

class Dummy : public QObject 
{ 
    Q_OBJECT 

public: 
    Dummy() { } 

public slots: 
    void askWork() { emit work(); } 

signals: 
    void work(); 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    qDebug() << "main thread id - " << QThread::currentThreadId(); 

    Worker worker; 
    worker.start(); 

    Dummy dummy; 
    QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection); 

    QTimer::singleShot(1000, &dummy, SLOT(askWork())); 

    return a.exec(); 
} 

Оба пути приводят к основной Идентификатор резьбы печатается в QThreaddoWork.

Кроме того, я думал о внедрении простого производителя-потребителя, но если это работает, есть ли причина, почему бы не сделать это таким образом?

ответ

3

Проблема заключалась в том, что приемник (QThread) «живет» в основном потоке, и, таким образом, цикл событий основного потока является тем, который выполняет этот слот.

из документации Qt:

С очереди соединений, слот вызывается, когда управление возвращается в цикл обработки событий нити, к которому принадлежит объект. Слот выполняется в потоке, в котором живет объект приемника.

Таким образом, решение, которое я нашел до сих пор, состояло в том, чтобы создать объект внутри run-потока() и вместо этого использовать его слоты. Таким образом, владелец получателя является потоком, а затем слот вызывается в контексте потоков.

0

Похоже, ваш рабочий поток завершен, прежде чем вы сможете даже вызвать любую функцию или отправить на нее сигнал.

+1

рабочий поток находится в его цикле событий из-за вызова exec() –

2

Для простого примера производителя-потребителя ознакомьтесь с записью в блоге от Bradley T. Hughes Treading without the headache.

2

В этом примере показано, как вы можете разделить класс Worker, чтобы он работал так, как вы хотите. Вам также необходимо предоставить ссылку или указатель на экземпляр Worker, чтобы иметь возможность подключиться к слоту.

class Worker : public QObject 
{ 
    Q_OBJECT 

public: 
    Worker() { } 

public slots: 
    void doWork() 
    { 
     qDebug() << "executing thread id - " << QThread::currentThreadId(); 
    } 
}; 

class WorkerThread : public QThread 
{ 
    Q_OBJECT 

public: 
    void run() 
    { 
     qDebug() << "new thread id " << QThread::currentThreadId(); 
     Worker worker; 
     exec(); 
    } 
}; 
1

Работник создан в основном потоке, и поэтому его события проходят в основном потоке. Вы должны переместить работника к его собственной теме:

Worker worker; 
worker.moveToThread(&worker); 
worker.start(); 

Теперь Qt знает worker жизнь в новом потоке, и в очереди событий в этом цикле событий.

 Смежные вопросы

  • Нет связанных вопросов^_^