From: Stefan Seefeld (seefeld_at_[hidden])
Date: 2003-06-07 09:40:03
William E. Kempf wrote:
>>so what ? the 'real' queue length is kept private and doesn't matter
>>much. It's the signaling of the semaphore that makes the change public.
> This is a race condition. It also occurs when extracting data from the
> queue. Whether or not the "'real' queue length" is private is not
> relevant, this race condition can lead to improper synchronization, such
> as trying to to extract data when there's no data left to extract.
Can you elaborate ? I can manipulate the queue as much as I want, the
availability of tasks will be known to consumers only when they are
signaled, not when the queue is non-empty. Where is the race condition ?
(Same argument for the empty slots)
Oh, of course the queue needs a mutex, too (as I said in my original mail),
just to protect the queue's internal structure, so a task extraction
may look like that:
template <typename T>
my_tasks.wait(); // decrements 'tasks' counter
Prague::Guard<Mutex> guard(my_mutex); // protects queue impl
T t = rep_type::front(); // copies next task (mustn't throw !)
rep_type::pop(); // removes task from queue impl
my_free.post(); // announce availability of a free slot
return t; // return t
The only tricky thing here is to make sure T's copy constructor doesn't throw.
>>And then there is the other semaphore I use to count the free slots,
>>which you didn't comment on, probably because it didn't fit into your
> No, actually, it strengthens the argument, because you now have even more
> state that needs to be synchronized to ensure against race conditions.
I don't understand this. The state in question is the difference between
the capacity of the queue and its current length. The only variable holding
this state is the semaphore ('my_free' in my code snippet). What do I need
to synchronize here ?