2015-11-15 2 views
0

Это часть основного.Основная нить не может получить форму сигнала рабочий поток

Этот код создает рабочего и рабочий рабочий.

Рабочий перемещается на рабочий рабочий стол.

Работник затем ждет сигнала, чтобы попросить его работать.

Работник излучает сигнал с результатом при выполнении задания.

Основной предполагается поймать этот сигнал и инициализировать переменную в основном.

main() 
{......... 
// This is the variable to be changed 
variableToGetFromWorker = 0; 

qDebug() << "Main thread: " << QThread::currentThreadId(); 

QThread workerThread; 
worker* stupidTom = new stupidTom(number); 

worker->moveToThread(&workerThread); 
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater); 
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob())); 
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int))); 

workerThread.start(); 
workerThread.wait(); 
...........} 


// This is a slot at main. Suppose to catch the signal from the worker 

void main::jobDone(int result) 
{ 
    qDebug() << "Changing variable"; 
    variableToGetFromWorker = result; 
} 

Это слот doJob рабочего.

void worker::doJob() 
{ 
    qDebug() << "worker::doJob invoked."; 
    qDebug() << "worker Thread:" << QThread::currentThreadId(); 

    // Doing Job here 

    emit jobDone(result); 
} 

Это QDebug результат

Main thread: 0x7ffff7fc6780 
worker::doJob invoked. 
worker Thread: 0x7fffdab44700 

В режиме отладки, я считаю, что программа останавливается на workerThread.wait() и никогда не идут на main::jobDone(int result). Какова причина?

Мало редактирования на основной код:

QThread workerThread; 
worker* stupidTom = new stupidTom(number); 

worker->moveToThread(&workerThread); 
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater); 
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob())); 
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int))); 
connect(stupidTom, SIGNAL(jobDone(int)), &workerThread, SLOT(quit())); 

workerThread.start(); 
workerThread.wait(); 

ответ

2

Пока сигналы должны вызывать слоты. Это не будет работать на wait() в основном потоке, который должен запускать слот или, в частности, сигнал jobDone.

Обязательно ознакомьтесь с разницей между QThread::exec() и QThread::wait() в вашем приложении. Обычно в реальном приложении ваш поток будет циклическим (работает), а поток, который запустил его, по-прежнему зацикливается. Цикл реализован в защищенном методе QThread::exec(). Обычно нам не нужно явно указывать exec(), но нам нужно разрешить выполнение потока. Вы можете сделать это, делая основную функцию использовать QEventLoop для зацикливания:

int main() 
{ 
//... 
    workerThread.start(); 
    QEventLoop eventLoop; 
// here you will probably want to hook-up QEventLoop::quit() slot 
// to eventually quit the process 
    int returnCode = eventLoop.exec(); 
//... 
    return returnCode; 
} 

И это тоже неправильно:

connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob())); 

Вместо этого вы должны создать свой собственный объект работы и сделать QObject::moveToThread для него. Вот хороший article. Таким образом, это должно выглядеть примерно так:

connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob())); 

Я, вероятно, понимаю, почему вы пытались запустить поток так, как указано выше. Это похоже на многие примеры на C++. Вы также можете сделать это в Qt, но вам также нужно понять, как именно вы будете ждать по завершении workThread. И Qt самый популярный способ взаимодействия между потоками - это сигналы и слоты. Вот почему мы должны использовать QEventLoop в основном. Но, конечно, есть альтернатива. Для более низкого уровня C++ вы можете использовать mutex и переменную условия для достижения того же. Или то же самое wait(), но тогда нет сигналов.

Также смотрите вывод отладки, независимо от того, действительно ли все соединения подключают надлежащие сигналы к слотам. В случае, если соединение отсутствует, печатается предупреждение.

+0

Я не понимаю причину добавления eventloop.Во-первых, я сожалею, что есть опечатка. Я использую именно то, что вы указали: connect (& workerThread, SIGNAL (start()), stupidTom, SLOT (doJob()) ;;. Рабочий объект - это объект, который я создаю только для передачи в поток. – tom

+0

Со ссылкой на статью, которую вы упомянули, я добавляю еще одно соединение: connect (stupidTom, SIGNAL (jobDone (int)), & workerThread, SLOT (quit())); '. Он также должен выйти из потока, когда освобождается 'jobDone()'. Предупреждение о соединении отсутствует. Я знаю, что 'emit jobDone (result);' действительно был выпущен. Но вполне уверен, что 'jobDone()' в main не вызывается, поскольку debug msg не печатается. – tom

+1

jobDone() не может быть вызван, потому что для сигналов кросс-потоков необходим цикл событий в принимающем потоке для запуска. Этот цикл событий также не должен быть заблокирован навсегда, поскольку это вызовет workThread.wait(). –

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