|
Boost : |
From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2006-09-19 10:38:35
"Peter Dimov" <pdimov_at_[hidden]> writes:
> Inventing mutex and condition variable algorithms is a slight cause of
> concern, I have to admit. The easiest way to get a free review of the
> algorithms is to post the code on comp.programming.threads and hope that
> someone of the experts there has enough time to look at them. CVs in
> particular have proven to be quite hard to implement correctly, and
> Alexander Terekhov's "8a" algorithm has emerged as a de-facto standard.
The mutex is simple, and you can see the code in
boost/thread/win32/basic_mutex.hpp on the thread_rewrite branch.
The algorithm is:
init():
active_count=0;
no semaphore
lock():
atomic increment active_count
if new active_count ==1, that's us, so we've got the lock
else
get semaphore, and wait
now we've got the lock
unlock():
atomic decrement active_count
if new active_count >0, then other threads are waiting,
so release semaphore.
locked():
return active_count>0
get_semaphore():
if there's already a semaphore associated with this mutex, return that
else
create new semaphore.
use atomic compare-and-swap to make this the associated semaphore if
none
if another thread beat us to it, and already set a semaphore, destroy
new one, and return already-set one
else return the new semaphore
The condition variable algorithm is actually a variant of Alexander Terekhov's
algorithm, and uses the same "gate" idea. However, my implementation uses
QueueUserAPC to wake up the waiting threads, rather than have them wait on an
event. This gets round what I think is a deficiency in Alexander's algorithm,
which is that once a notify operation is underway, no new threads can wait on
the condition until all notified threads have actually woken up, and the last
one has "opened the gate". By using QueueUserAPC, we can notify the threads to
wake up, and open the gate, without having to wait for all the notified
threads to resume. The flipside is that the first thread to wait is the first
to be notified. Whether this is a good or bad thing is open to debate.
The code is in boost/thread/win32/condition.hpp on the thread_rewrite branch.
The algorithm is as follows:
waiting_list_node:
waiting_list_node* next, prev
HANDLE thread_handle
bool notified
waiting_list: doubly-linked list of waiting_list_node
gate: mutex
init():
waiting_list.next=waiting_list.prev=&waiting_list
init mutex
wait(external_mutex, timeout):
create a new waiting_list_node
new_node.thread_handle=thread handle for this thread
new_node.prev=&waiting_list
lock(gate)
new_node.next=waiting_list.next
waiting_list.next=&new_node
new_node.next->prev=&new_node
unlock(external_mutex)
unlock(gate)
// Any APC will break the sleep, so keep sleeping until we've been
// notified, or we've timed out
while(!atomic_read(new_node.notified)
&& SleepEx(milliseconds_until(timeout), true)==WAIT_IO_COMPLETION);
lock(gate)
unlink(new_node)
unlock(gate)
lock(external_mutex)
return new_node.notified // did we timeout, or were we notified?
unlink(node)
// unlink the node from the list
node.next->prev=new_node.prev
node.prev->next=new_node.next
node.next=node.prev=&node
notify_and_unlink_entry(node)
atomic_set(node->notified,true)
unlink(node)
// wake the node's thread by queueing an APC
// the APC func doesn't have to do anything to wake the thread
QueueUserAPC(NOP(),node->thread_handle)
notify_one()
lock(gate)
if(waiting_list.prev==&waiting_list) do nothing
else
notify_and_unlink_entry(waiting_list.prev)
unlock(gate)
notify_all()
create a waiting_list_node for new_list
lock(gate)
// transfer the existing list over to new_list
new_list.prev=waiting_list.prev
new_list.next=waiting_list.next
new_list.next->prev=&new_list
new_list.prev->next=&new_list
// the waiting_list is now empty
waiting_list.next=waiting_list.prev=&waiting_list
unlock(gate) // noone has to wait for us any more
while(new_list.prev!=&new_list) // loop until the captured list is empty
notify_and_unlink_entry(new_list.prev)
I'll post the algorithms over at comp.programming.threads for comment.
Anthony
-- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk