OOP: Lock-free queue for two threads
Posted: Sun Apr 06, 2008 4:25 pm
At least I hope it's safe... But no warranties!
Code: Select all
; Safe for either
; 1 pop/peek-only thread and 1 push-only thread
; or
; 1 thread (no restrictions)
; Note: \Free() is not threadsafe
Interface IQueue
Push(*Data.l)
Pop.l()
Peek.l()
Free.l()
EndInterface
Structure SQueue
*Methods.l
Size.l
*Buffer.l
*ReadPtr.Long
*WritePtr.Long
EndStructure
Procedure CreateQueue(Items.l)
Protected *Q.SQueue = AllocateMemory(SizeOf(SQueue))
*Q\Methods = ?IQueue_VTable
*Q\Size = Items*4
*Q\Buffer = AllocateMemory(Items*4)
*Q\ReadPtr = *Q\Buffer
*Q\WritePtr = *Q\Buffer
ProcedureReturn *Q
EndProcedure
Procedure IQueue_Push(*t.SQueue, *Dta.l)
; Don't write past the read pointer
While *t\WritePtr+4 = *t\ReadPtr Or (*t\ReadPtr = *t\Buffer And *t\WritePtr+4 - *t\Size = *t\Buffer)
Delay(1)
Wend
*t\WritePtr\l = *Dta
If *t\WritePtr+4 - *t\Size = *t\Buffer
*t\WritePtr = *t\Buffer
Else
*t\WritePtr+4
EndIf
EndProcedure
Procedure IQueue_Peek(*t.SQueue)
; Don't read past the write pointer
While *t\ReadPtr = *t\WritePtr
Delay(1)
Wend
ProcedureReturn *t\ReadPtr\l
EndProcedure
Procedure IQueue_Pop(*t.SQueue)
Protected *Dta.l
*Dta = IQueue_Peek(*t)
If *t\ReadPtr+4 - *t\Size = *t\Buffer
*t\ReadPtr = *t\Buffer
Else
*t\ReadPtr+4
EndIf
ProcedureReturn *Dta
EndProcedure
Procedure IQueue_Free(*this.SQueue)
FreeMemory(*this\Buffer)
FreeMemory(*this)
EndProcedure
DataSection
IQueue_VTable:
Data.l @IQueue_Push()
Data.l @IQueue_Pop()
Data.l @IQueue_Peek()
Data.l @IQueue_Free()
EndDataSection
;- Example ----------------
Procedure PushStuff(Queue.IQueue)
Protected I
For I = 0 To 20000
Queue\Push(I)
Next
EndProcedure
Procedure PopStuff(Queue.IQueue)
Protected I
OpenFile(0, "c:\out.txt")
For I = 0 To 20000
WriteStringN(0, Str(Queue\Pop()))
; Queue\Pop()
Next
CloseFile(0)
EndProcedure
Global Queue.IQueue = CreateQueue(1024*4)
T1 = CreateThread(@PushStuff(), Queue)
T2 = CreateThread(@PopStuff(), Queue)
WaitThread(T1)
WaitThread(T2)
Queue\Free()