|
Boost : |
From: Ben Hutchings (ben.hutchings_at_[hidden])
Date: 2004-09-29 05:36:52
John Torjo <john.lists_at_[hidden]> wrote:
<snip>
> But now, by looking again at atomic_conditional_increment. I'm not a
> threading expert, but it seems pretty costly as it is implemented
> now. Could it not go multiple times (n>=2) thorughout the for?
Yes.
> Current implementation:
>
> inline long atomic_conditional_increment(long volatile & value)
> {
> for(;;)
> {
> long tmp = value;
> if(tmp == 0) return 0;
> if(InterlockedCompareExchange(&value, tmp + 1, tmp) == tmp)
> return tmp + 1;
> }
> }
>
>
> Couldn't it become:
>
> inline long atomic_conditional_increment(long volatile & value)
> {
> long tmp = value;
Suppose we read the count as 2 here...
> if(tmp == 0) return 0;
...and that another thread decrements the count to 1 around here...
> long new_val = InterlockedCompareExchange(&value, tmp + 1, tmp);
> if(new_val == tmp) return tmp + 1;
...so that InterlockedCompareExchange fails and returns 1, so this
doesn't return; and suppose that another thread decrements the count
to 0 around here...
> else return InterlockedIncrement(&value);
...then this increments the count to 1, which is wrong.
> }
The increment has to be conditional on the count being non-zero, and
neither the Win32 API nor the x86 processor (AFAIK) can perform that
atomically. So the loop is unavoidable.
There is room for a slight optimisation in that the value returned
by InterlockedCompareExchange can be used the next time round:
inline long atomic_conditional_increment(long volatile & value)
{
long old = value, older;
do
{
if (old == 0)
return 0;
older = old;
old = InterlockedCompareExchange(&value, old, old + 1);
}
while (old != older);
return old + 1;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk