[fpc-devel] LockFree Queue algorithm
Martin Friebe
fpc at mfriebe.de
Sun Jan 27 16:49:54 CET 2008
You will need to test it, but the following may also work
procedure tFlQueue.push(const tm : tNodeQueue);
var
newTemp,
lastTail,
newTail : integer;
begin
newTemp := temp;
while newTemp >= fsize begin
// if it is true, every thread is going to attempt to fix it, before
doing the increment.
// this means no thread will increase the value
// => one thread will to succeed (since the only reason "temp NE
newTemp" is that temp has been decreased)
// newTemp is bigger than fsize, so the result can not become negative.
interlockedCompareExchange(pointer(temp),pointer(newTemp-fsize),pointer(newTemp));
newTemp := temp;
end;
newTemp:=interlockedIncrement(temp) mod fsize; // make sure we are
always in range
lastTail:=newTemp-1;
if lastTail < 0 then lastTail := fsize -1;
setObject(lastTail,tm); // you can remove the "mod" in setobject
repeat
pointer(newTail):=interlockedCompareExchange(pointer(tail),pointer(newTemp),pointer(lastTail));
until (newTail=lastTail);
end;
The "repeat" at the end does still work. In order to set "tail" to "0"
(newTemp=0) => "tail" must first get "9" (as lastTail will be 9).
Only flaw is, if fsize is close enough to the upper data tpye boundary,
and enough threads do InterLockedInvrement, (after all having
simultaneously passed the repeat at the start), then you can still run
over the boundary.
However this can only happen if you have more threads, than
(upperBoundary - fsize).
So you can specify, that it is save up to this amount of parallel threads
IMHO the unit should have a warning (in the comments) that there it is
the users responsibility *not* to store more elements than fsize. There
is no check, and you will loose data, if you try to do so.
But as I said, no warranty that this will work, I haven't done any
testing...
Martin
DarekM wrote:
> Martin Friebe pisze:
>> What about a long running (eg daemon) application?
>>
>> If temp/tail hits the upper boundary of Integer?
>>
>> (If I understand it correctly)
>> I don't know if interlockedIncrement gives a boundary error, but if not,
>> it still fails.
>> - With currently integer, it gets a negative value, once crossing
>> 0x7fffffff, and SetObject will attempt to read/write out-of-bounds
>> memory.
>> - Assuming temp/tail being unsigned: it will go from 0xffffffff to 0.
>> "0xffffffff mod fsize" may return a value greater 0, "0x00 mod fsize"
>> will be zero. You make an unexpected jump within the list.
>>
>
>
> Thats right.
> But I can avoid this.
> 1. make length of tab equal power of two
> 2. use longword instead of integer
> 3.instead MOD use result:=tab[lp and fmask];
> and fmask:=$F or $FF or $FFF
>
>
> Thanks to find bug.
>
>
> Darek
>
>
>
>
> _______________________________________________
> fpc-devel maillist - fpc-devel at lists.freepascal.org
> http://lists.freepascal.org/mailman/listinfo/fpc-devel
More information about the fpc-devel
mailing list