PDA

View Full Version : Public functions in a QThread class: safe?



dmginc
31st January 2011, 07:49
The question I am about to ask was actually asked in this thread: http://www.qtforum.org/article/32113/qthread-questions.html

But wasn't really properly answered...

Here is some code to explain the question:

Subclassed from QThread:

thread::run()
{
while(1)
{
if(someCondition)
privateMember++;
}
}


thread::getPrivateMember()
{
return privateMember;
}

Q: Is it necessary to protect privateMember with mutexes in the above case [as in a lock()/unlock() pair in run() and a QMutexLocker in getPrivateMember()] ?

OR, is privateMember automatically protected seeing as the "get" function is a member function of a QThread-derived class. In other words, run() and getPrivateMember() will never run at the same time and are thus protected?

Can someone shed some light on this?

Cheers

helloworld
31st January 2011, 09:01
1. It's not safe, since objects with different thread affinity can call getPrivateMember().

2. You should use a wait condition instead of busy looping.
QWaitCondition


3. I would recommend that you instead subclass QObject, create a QThread instance and use moveToThread() to set the thread affinity of your object, as mentioned in this article:

http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

With this approach + using signal and slot connections you can avoid a lot of these issues.



Usually, this means simply changing your class to inherit from QObject instead of QThread and, possibly, changing the class name. QThread has a started() signal that you can connect to when you need to perform some initialization. To actually have your code run in the new thread context, you need to instantiate a QThread and assign your object to that thread using the moveToThread() function.

high_flyer
31st January 2011, 09:05
Q: Is it necessary to protect privateMember with mutexes in the above case [as in a lock()/unlock() pair in run() and a QMutexLocker in getPrivateMember()] ?
There is a simple rule to it:
If the variable can be accessed by at least two threads at the same time, it has to be guarded by a mutex, or semaphore or similar mutual exclusion mechanism.
This has nothing to do with variable access privileges (public/protected/private).

helloworld
31st January 2011, 09:10
On second thought, a wait condition is perhaps not what you need in this case. But busy looping is still a bad idea, and you can still use above mentioned approach taking advantage of Qts signal/slots mechanism instead.

wysota
31st January 2011, 09:20
If privateMember is of type QAtomicInt, it doesn't have to be protected. If it is a regular int, all what has already been said here applies.

dmginc
31st January 2011, 09:57
If privateMember is of type QAtomicInt, it doesn't have to be protected. If it is a regular int, all what has already been said here applies.

Thanks for that. This is the answer to the question I wanted to know :)


On second thought, a wait condition is perhaps not what you need in this case. But busy looping is still a bad idea, and you can still use above mentioned approach taking advantage of Qts signal/slots mechanism instead.

Perhaps the "if" condition in my example code wasn't the best choice. I merely wanted to show a private member of the class being altered in run().


1. It's not safe, since objects with different thread affinity can call getPrivateMember().


So basically, when I call the "get" public function from another thread, it is executed at the same time as run() (that's what I wasn't sure of..)? In other words, run() does not block until the "get" function returns?

Thanks again.

wysota
31st January 2011, 10:33
So basically, when I call the "get" public function from another thread, it is executed at the same time as run() (that's what I wasn't sure of..)?
Not necessarily but there is no guarantee that it doesn't.


In other words, run() does not block until the "get" function returns?
It's just a function call like any other. Why would anything block? Especially that the QThread object lives in the same thread as the method calling it.