Re: pthread_cond_wait and pthread_cond_signal
- From: Dave Butenhof <david.butenhof@xxxxxx>
- Date: Tue, 28 Mar 2006 22:08:22 -0500
eksamor wrote:
I have this globally in a file:
pthread_mutex_t mutex_queue = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t when = PTHREAD_COND_INITIALIZER;
I have a thread A that initialy finds a queue empty and therefore calls
pthread_cond_wait(&when, &mutex_queue). When an element is inserted
into the queue it should wake up and print its content.
Then I start 3 threads (T1,T2,T3) that each inserts an element into the
queue and afterwards each call:
pthread_cond_signal(&when);
But thread A only continues after T3 calls pthread_cond_signal(&when).
Why does it not wake up after T1 calls pthread_cond_signal(&when)??
For some reason the queue gets all three elements inserted before the
thread A wakes up and begins to remove elements from the queue.
what am I missing?
The best answer is the simple asynchronous programming principle that "synchronization is not scheduling".
You are inferring (and expecting) SCHEDULING based on SYNCHRONIZATION operations, and that's not what you should expect or what you should want.
Synchronization ensures safety of your data through asynchronous operations. Scheduling determines how those asynchronous operations meet "in space time". The asynchronous operations may be simultaneous, or interleaved in any order, depending on how your operations map into the physical operation of the hardware -- and if you've correctly coded your synchronization it doesn't matter a bit to you or your application.
If it doesn't matter to your application that you can enqueue 3 entries before one is removed, then don't worry about it: you're just making trouble for yourself. If your program won't work that way, then there's clearly a problem; you haven't supplied the SYNCHRONIZATION that your application requires. So go back and think over the problem again. (And if you find out that you can change the design so it doesn't matter, you'll be better off, because your application can be scheduled more flexibly and more efficiently with fewer synchronization constraints.)
There's no way to guess from your post whether your code is correct. But one possible legitimate sequence of operations is this: you create 4 threads that will each immediately lock the mutex. Thread T1 gets the lock, while T2, T3, and A queue waiting for it to release. As each thread unlocks, the next waiter, in order, is released and acquires the lock. T2 and T3 each add an item to the queue, and signal the condition variable "when". NOW, A gets to run, locks the mutex, and tests the predicate condition ("queue not empty"); finding the condition true, it immediately dequeues an item without ever needing to wait on the condition variable at all. OR... A runs first, locks the mutex and finds the queue empty, waits on "when". T1, T2, and T3 start, all trying to lock the mutex. One wins, queues an entry, and signals the condition variable. A wakes, and immediately tries to lock "when". Finding it locked, it joins the queue of waiters. T2 and T3 are awakened, each adding their queue entry and signalling again -- neither signal operation does anything as there is no waiter. Finally, when the last unlocks, A is scheduled, acquires the lock, and finds the waiting queue entries.
If either of these is not a "reasonable" and acceptable sequence for your application, then your synchronization scheme is inadequate to express your intent and you need to rethink it. But first, stop and think whether it's really just fine. Is it critical that each queue entry be consumed before another added? Are you CREATING the queue entry while holding the lock, or only holding it for the bare minimum time required to enqueue it? And if you are holding it longer, do you really need to? If creating or processing an entry is substantially longer than the actual queue operations, you may be able to gain productive parallelism just by making the critical section (the area where you hold the mutex) smaller.
Synchronization (and scheduling predictability) are not goals, but necessary evils. Apply them where required; but be miserly with them. And don't let yourself be caught off guard when you observe an unexpected execution order -- instead, think it through and see whether it's reasonable or acceptable. If either test fails, there's a bug; the former likely of implementation, the latter probably of design.
.
- References:
- pthread_cond_wait and pthread_cond_signal
- From: eksamor
- pthread_cond_wait and pthread_cond_signal
- Prev by Date: Re: pthread_cond_wait and pthread_cond_signal
- Next by Date: printf and mutex
- Previous by thread: Re: pthread_cond_wait and pthread_cond_signal
- Next by thread: printf and mutex
- Index(es):
Relevant Pages
|
|