[Qt-interest] Is it safe to connect different threads by Qt::DirectConnection?
Mihail Naydenov
mlists at ymail.com
Tue Dec 8 10:24:00 CET 2009
>
>From: donglongchao <donglongchao at 163.com>
>To: Mihail Naydenov <mlists at ymail.com>
>Cc: Qt Devel <qt-interest at trolltech.com>
>Sent: Tue, December 8, 2009 5:13:36 AM
>Subject: Re: [Qt-interest] Is it safe to connect different threads by Qt::DirectConnection?
>
>
>在2009-12-06,"Mihail Naydenov" <mlists at ymail.com> 写道:
>>
>>>>
>>>>You should post some code, I (completely) fail to understand your configuration, and what the problem is.
>>>
>>>class workthread:QThread
>>>{
>>> public slot:
>>> void slot_fun()
>>> { some time-consuming code here;}
>>>}
>>>void workthread::run()
>>>{
>>> QTimer timer;
>>> QObject::connect(&timer,SIGNAL(timeout()),this,SLOT(slot_fun()));
>>> timer.start(...);
>>>}
>>>GUI thread(main thread)
>>>int main(int argc,char *argv[])
>>>{
>>> mythread = new workthread;
>>>}
>>>So now I want the slot function slot_fun() to run in the work thread ,not in the GUI thread.According to the documents,if the fifth parameter is not set,slot_fun() will run in the GUI thread which will cause the UI unresponsive.If the fifth parameter is set to be Qt::DirectConnection, slot_run() will run in work thread.This is what I need.But I want to know if it is thred-safe to do like this or if there is a better way I do not know.
>>
>>
>>It seams you misinterpreted the documentation.
>>
>>"The fifth" by itself, cannot change where (in which thread) the the slot is executed.
>>Where it is executed depends on where the qobject "lives". In general qobjects live in the thread they are created in the first place until they are movedToThread.
>>
>>Now in your example you have two qobjects: workthread and QTimer
>>
>>You create workthread instance in main => mythread "lives" in the man (GUI) thread => all slots will be executed in the main thread.
>>You create QTime instance in QThread::run() - all objects, created in QThread::run() live in a different thread (understandably, considering this is "the code to be ran on a different thread").
>>
>>Now, you indeed connect objects from diff. threads, but the other way around!
>>
>>You send (thread safe) requests "from a different thread" to be handled in the gui thread! (slot in a object, living in the main thread)
>>
>>Note, again however, no option in qobject::connect can possibly change the thread position of the objects. It is again the other way around - connect does not change the thread affinity of the objects - its changed based on it!
>>(this is, AutoConnection (the default) will be "modified" to be Direct if objects are on the same thread, and Queued if on diff.)
>>
>>Anyway here is somewhat reversed (and working) example of your code that does do the heavy work in slot in a diff thread.
>>It is reversed because it creates the timer in the main thread and an work-doing-object on another.
>>
>>#include <QtGui>
>>
>>class worker : public QObject
>>{
>> Q_OBJECT
>>public slots:
>> void slot_fun()
>> {
>> //some time-consuming code here
>>
>> for(int i=0; i < 1000; ++i)
>> {
>>
>> if(i%100 == 0)
>> qDebug()<<"doing work..."<<i;
>> }
>>
>> }
>>
>>};
>>
>>#include "main.moc"
>>
>>int main(int argc, char *argv[])
>>{
>> QApplication a(argc, argv);
>>
>> QTimer timer;
>>
>> QThread workerthead;
>> workerthead.connect(&a,SIGNAL(aboutToQuit()), SLOT(quit()));
>>
>> worker laborer;
>> laborer.moveToThread(&workerthead);
>> laborer.connect(&timer,SIGNAL(timeout()),SLOT(slot_fun()));
>>
>>
>> timer.start();
>> workerthead.start();
>>
>> QWidget ui;
>> ui.show();
>>
>> bool result = a.exec();
>> workerthead.wait();
>> return result;
>>}
>>
>>Now, its not necessary for QTimer to be in the main, the important thing is - through the live of the app you can aways (safely) call the fun_slot()
>>from any object and from any thread and have work done in parallel !
>>
>
>Thank you very much,Mihail Naydenov.But I have another question here.According to the documents,If you are calling a function on an QObject subclass that doesn't live in the current thread and the object might receive events, you must protect all access to your QObject subclass's internal data with a mutex; otherwise, you may experience crashes or other undesired behavior.
>If I connect a signal of GUI thread to a slot of another object lives in workthread by the fifth parameter set default ,do I need to protect the the object's internal datas when the slot access them?I think the slot will run in the workthread and the event loop of the workthread will manage this signal/event and handle the execution of the slot.It will not conflict with the other signal/event/slot of the workthread(I mean we do not need QMutex or something like that here).Is it right?
Yes, if you communicate only trough slots you do not need to protect the data, because slot and events execution is serialized and its aways on the thread the object lives on.
Note, however the word *communicate* - this is, not only you have to submit the work trough signals and/or events but also avoid setting any state/properties to that object from another thread directly (for instance trough a function call).
The sentence of the documentation warns about exactly that.
This is, once the object is on another thread avoid object->setSomething(value) calls.
(because, at the same time, the objects might be handling slots/events (in own thread) that access this property!)
If you need to set properties that way - protect them with a mutex. Thats it.
(Of course the other way is to set all state in the constructor, make the object immutable, and avoid the mutex)
MihailNaydenov
>
>>AFAIK this is the only way to have work done in a slot on a diff thread.
>>
>>(again)
>>At Qt team, please add at least one example about this technique!
>>
>>MihailNaydenov
>>
>>
>>>>
>>>>>...
>>>>>
>>>>>Longchao.
>>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>>
>
>
>
________________________________
"雪见"杨幂邀你共品3D国韵网游《天下贰》,海报免
More information about the Qt-interest-old
mailing list