Boost logo

Boost :

Subject: Re: [boost] Boost sprint: #3407 boost::call_once not re-entrant (at least in win32)
From: Anthony Williams (anthony.ajw_at_[hidden])
Date: 2009-11-24 06:55:49


Anthony Williams <anthony.ajw_at_[hidden]> writes:

> Gottlob Frege <gottlobfrege_at_[hidden]> writes:
>
>> On Mon, Nov 23, 2009 at 12:26 PM, Anthony Williams
>> <anthony.ajw_at_[hidden]> wrote:
>>>
>>> You don't need a new event. If the event is set it means "check the
>>> status". So thread enters call_once. Sees status is "running" and waits
>>> on the event. When the event is set it wakes and checks status. If
>>> status is complete, we're done. If status is running, wait for the same
>>> event again. If status is "not done", set it to running, reset the event
>>> and run the function. On completion, set status to "complete" and set
>>> the event. On exception, set status to "not done" and set the event.
>>>
>>> I'll code it up.
>
>> It is worth giving it a try, but we went down that road in
>> pthreads-win32. I think the hard part is the 'reset the event' step.
>> There were problems with whether the event should be manual or
>> auto-reset, and with the 3rd thread in looping without waiting, etc.
>> IIRC manual means you have a hard time knowing when to reset (ie did
>> everyone or ANYONE wait yet - you could close too early), auto-reset
>> meant that each 'waker' needed to wake the next one, etc. I can't
>> remember what was really bad about chaining the waking of the waiters.
>> Maybe it just felt a bit queasy.
>
> I can see that there's potential for these problems. I also think I can
> see a way round them. I'll find out when I'm done coding.

I've checked in a new version on trunk

https://svn.boost.org/svn/boost/trunk/boost/thread/win32/once.hpp

This version only allocates an event if there is contention. The event
(if there is one) is reset just before invoking the function in the one
thread that gets to run it. It is set after the completion flag is
set. The event is deallocated when the last thread that is using it
exits call_once. If a thread exits because f() threw an exception then
this is counted separately in order to avoid prematurely destroying the
event. If f() throws every time it is called then the event will stick
around until the flag is destroyed.

It's not as tidy as I'd like, but I think the logic is sound.

Anthony

-- 
Author of C++ Concurrency in Action | http://www.stdthread.co.uk/book/
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk