Path: csiph.com!usenet.pasdenom.info!news.albasani.net!.POSTED!not-for-mail From: aminer Newsgroups: comp.programming.threads,comp.programming Subject: Here is my reasonning again Date: Thu, 24 Apr 2014 20:28:07 -0700 Organization: albasani.net Lines: 198 Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: news.albasani.net ht8uK5Z26aqr+czCOfM5cnfc3GzFQQpWqxhT4eBEFQlbzKjwbjVJzGsOZy3zK1khbLr6l5FtFjyC55EVIyEYiw== NNTP-Posting-Date: Fri, 25 Apr 2014 00:28:19 +0000 (UTC) Injection-Info: news.albasani.net; logging-data="fgTJzJwV697nBjazShxZk64JaQsvnOEh6vNUCG/E4QTXQJYo7XzvOZuXKUUx5J7ersuStY+Y7PSP1I841Rx/ZA++JaCRibpr6rOuH4kaxdGQX9V/oXeF/T5C2MSqDieS"; mail-complaints-to="abuse@albasani.net" User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 Cancel-Lock: sha1:DTATEpCNLLxrrU4XfjcLF1xSnYo= Xref: csiph.com comp.programming.threads:2255 comp.programming:4320 Here is my reasonning again, i think my reasonning is correct so my proof is correct... please read again... Hello, Question: Amine, how can we know that your algorithm of your new concurrent FIFO queue works ? is it formally proved ? Answer: You can simply reason about the algorithm to prove that it is correct , i will do it in front of you... You can download the source code of the algorithm from here: http://pages.videotron.com/aminer/ We begin by the pop() method, its source code look like this: === function TWQueue.push(tm : long):boolean; var lastHead,newtemp:long; i,j:integer; begin if getlength >= fsize then begin result:=false; exit; end; newTemp:=LockedIncLong(head); lastHead:=newtemp-1; repeat asm pause end; until fcount1^[lastHead and fMask].flag=0; setObject(lastHead,tm); fcount1^[lastHead and fMask].flag:=1; if fwait then sema.signal; result:=true; end; === you have to know that "fsize" is fixed to the length of the queue minus a "margin" that is equal to 1000 , that means that it's limited to 1000 threads in total that can run at the same time the push(), but you can vary the margin to higher the number of threads that can run the push() at the same time... So if getlength equal fsize-1 that means that 1000 threads can cross because "if getlength >= fsize" can be false at the same time, but even if it is false at the same time , there a margin of 1000 threads, so my reasonning is correct here. Now we look at the rest of the code... Every cell of the array based queue look like this: type cell = record obj:long; flag:long; {$IFDEF CPU32} cache:typecache2; {$ENDIF CPU32} {$IFDEF CPU64} cache:typecache3; {$ENDIF CPU64} end; It's cache padded to a cache-line size and the array is aligned on 64 bytes so that to avoid false-sharing... After that we increment the "head" like this with an atomic increment... newTemp:=LockedIncLong(head); lastHead:=newtemp-1; and if fcount1^[lastHead and fMask].flag=0 that means there is no item in the cell , we will write the item on the cell by doing this: setObject(lastHead,tm); and after that we set the flag of the cell to 1 so that the pop() can read from it when it's set to 1 like this: fcount1^[lastHead and fMask].flag:=1; so as you have noticed i have reasonned and explained to you the push() side, and i think my reasonning is correct here. Now we will look at the pop() side, here is the code of the pop() side: === function TWQueue.pop(var obj:long):boolean; var lastTail,newtemp,newtemp1,newtemp2 : long; begin if fwait then sema.wait; repeat newtemp1:=tail; newtemp2:=newtemp1+1; if newtemp2<=head then else begin result:=false; exit; end; if CAS(tail,newtemp1,newtemp2) then break; sleep(0); until false; lastTail:=newtemp1; repeat asm pause end; until fcount1^[lastTail and fMask].flag=1; obj:=getObject(lastTail); fcount1^[lastTail and fMask].flag:=0; result:=true; end; == The very first thing to know on the pop() side is that we must increment the "tail" everytime but how can we increment the tail without going over the "head", this is why in my invention i have used a lockfree mechanism like this == repeat newtemp1:=tail; newtemp2:=newtemp1+1; if newtemp2<=head then else begin result:=false; exit; end; if CAS(tail,newtemp1,newtemp2) then break; sleep(0); until false; == It's like in lockfree algorithms , i have to copy and memories the "tail" into the newtemp1 variable and after that increment newtemp1 , so if newtemp1+1 is less or equal to "head" that means we are correct and we have not go over the head , after that with a lockfree mechanism we will test with a CAS that tail is still equal to newtemp1 to be able to increment the "tail" , so my reasonnning is correct here. After that we have to wait to see if there is an item in the cell by doing this: repeat asm pause end; until fcount1^[lastTail and fMask].flag=1; If there is an item on the cell we will get it and set the flag of the cell to 0 to say to the push() threads that they can push() to this cell by doing this: obj:=getObject(lastTail); fcount1^[lastTail and fMask].flag:=0; So as you have noticed this is my new algorithm and i have presented to you my reasonning to prove to you that my algorithm is correct, and i think my algorithm is correct. Thank you, Amine Moulay Ramdane.