
On Mon, Nov 23, 2009 at 6:46 AM, Anthony Williams <anthony.ajw@gmail.com> wrote:
Gottlob Frege <gottlobfrege@gmail.com> writes:
Crikey that's a lot of code for a simple feature!
Yes, unfortunately. I've done it different ways in the past. I could probably give you a version that didn't build a linked list of nodes. But there are trade-offs.
I would just go for adding a "running" state to the flag value. If the flag is not "complete", set it to "running" using CAS. If we set it, then run, otherwise create an event, store it in the once_flag object (using CAS in case another waiter already stored an event), check the flag is still "running" and then wait for our event. When the event is triggered, loop again (to run the function if it threw last time).
Once the thread that runs the function has completed the function call it can then set the flag to "complete", and set the event if there is one. If the function throws then the flag can be set back to "not started" and the event set if there is one.
Anthony --
Yes, I've done it this way. You will have problems destroying the event. ie knowing who and when to destroy it. I don't think leaving the event handle leaking would be OK. You need to count it. It really isn't *too* hard, until you run into exceptions. Then you need to open the event and reset the once_flag. But now you need another event for the new attempt (you can't use the same event as you are not sure if all threads from the first attempt have even waited yet). So where do you store the event!? Using nodes solves that. You can also solve it by using what I call a 'branding gate' - the gist of it at least, from memory: as each thread enters, it increments a waiting count and/or the 'running' flag (lo/hi halves of an int, say). But on retry (after an exception) you don't just reset the running flag, you increment it - and 'running' becomes whether the flag is odd or even. This way every entry or wait is 'branded' with a unique value. You can then use the unique value to look up a named mutex (or named event). Windows takes care of ref counting for you. You still end up creating a global named handle, but it can be deferred until contention is detected. See also the discussion thread starting at http://www.sourceware.org/ml/pthreads-win32/2005/msg00016.html. This also ended in a node-based solution, although I think it used event handles on each node (iiuc). I never added my branding gate version to the discussion (hadn't figured it out at the time). A branding gate version does at least look somewhat simpler. Still not as straightforward as what you currently have. P.S. the other version you have (for posix) using the thread-local (based on the Google version) looks interesting as well. I think it would be nice to incorporate that, but avoid the global lock that is used. Tony