QWaitCondition::wait() and QMutex question
-
I have a question regarding QWaitCondition::wait() and the QMutex that it needs:
According to the docs, QWaitCondition::wait() requires the calling thread to pass a pointer to a QMutex and that QMutex needs to be "locked" by the calling thread at the moment of the call. It's not said explicitly in the docs, but I assume that I can not use an arbitrary QMutex. Instead, I assume, all threads which want to wait() on the same QWaitCondition object also need to lock and pass the same "global" QMutex object. Right?
Entering the wait() from different threads with the same QMutex is okay, because, according to the docs, wait() will unlock the QMutex when the "waiting" state is entered. So the first thread can lock the QMutex and enter the wait(). Then the second thread can lock the QMutex and also enter the wait(). Then the third thread. And so.
But there is one thing that bothers me:
According to the docs, the QMutex will be locked again when wait() returns! This might be okay, when QWaitCondition::wakeOne() is called. Only one thread will wake up and this thread will have the QMutex locked at the moment when wait() returns. But what about QWaitCondition::wakeAll()? If multiple threads were waiting, all these threads will wake up at the same time, when wakeAll() gets called! It's not possible that multiple threads have the QMutex locked at the same time. So which of these threads will have the QMutex locked? Is it undefined?
But then how do I know which of threads that were waiting now needs to unlock the "global" QMutex?
-
As far as I know the thread is chosen arbitrarily. Each thread is woken, so once the first thread that is woken releases its lock the next thread continues execution, etc.
-
So do I get this right? QWaitCondition::wakeAll() doesn't wake all waiting threads right away, but instead will only wake a single thread (chosen arbitrarily) and give that thread ownership of the QMutex. As soon as the first thread that was woken up releases the QMutex, the next thread will be woken up. And so on...
If so, what happens if (a) there is another QWaitCondition::wakeAll() call while the previous wakeAll() is still in the process of waking up the threads or if (b) new threads start to wait for the QWaitCondition while a QWaitCondition::wakeAll() is still process of waking up the threads ???
-
If there is another QWaitCondition::wakeAll() call that will only affect the threads that have already been woken up by the first call and then gone back to sleep by calling wait() again. The other threads would have woken up in any case, so that's not changed by the new call to QWaitCondition::wakeAll(). There's no per-thread counter in the wait condition saying how many times that thread should be woken up, it's just about waking up the threads that are currently in wait() on the same wait condition.
See http://qt-project.org/doc/qt-4.8/qwaitcondition.html#details
-
Thanks for the info. But there is one thing that still isn't clear to me and I think the docs aren't precise on this: If I don't need the additional Mutex locking in my application (I just want several threads to be "blocked" until another threads triggers the wakeup and I want them all to wake up as soon as possible when that happens), can each thread use its own QMutex instance to call QWaitCondition::wait() or is it a requirement that all threads, which want to wait() on the same QWaitCondition object, need to enter wait() using the exactly same QMutex?
-
Good question, I don't know if each call to wait() on the same wait condition can use a different mutex. If it's not possible you could always resort to using multiple wait conditions, one for each thread that blocks, and put them in a list. Then when you want them all to wake up you call wakeOne() on each wait condition in the list.