A tiny example I have found on the French forum I have took time to re-write OOP style. The original example is from Microdevweb. (I hope you don't mind)
It's an example about synchronizing threads using a Double Barriers tactic.
I hope you will find this useful and/or instructive.
Best regards
StarBootics
Code: Select all
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; AUTOMATICALLY GENERATED CODE, DO NOT MODIFY
; UNLESS YOU REALLY, REALLY, REALLY MEAN IT !!
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Code generated by : Dev-Object - V1.7.2
; Project name : Barriers - The runners example
; File name : Barriers - OOP.pb
; File Version : 1.0.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : 19-03-2022
; Last update : 19-03-2022
; Coded for PureBasic : V6.00 Beta 5
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming Notes
;
; Based on Microdevweb's original example (French Forum)
;
; https://www.purebasic.fr/french/viewtopic.php?p=206088
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
DeclareModule Barriers
Interface Barriers
Wait()
Free()
EndInterface
Declare.i New(ThreadCount.i)
EndDeclareModule
Module Barriers
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<
Structure Private_Members
VirtualTable.i
Barrier1.i
Barrier2.i
Mutex.i
ThreadCount.i
Counter.i
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Wait operator <<<<<
Procedure Wait(*This.Private_Members)
LockMutex(*This\Mutex)
*This\Counter + 1
If *This\Counter = *This\ThreadCount ; If all Threads have arrived at barrier #1
WaitSemaphore(*This\Barrier2) ; Close Barrier #2
SignalSemaphore(*This\Barrier1) ; Open Barrier #1
EndIf
UnlockMutex(*This\Mutex)
WaitSemaphore(*This\Barrier1); Close Barrier #1
SignalSemaphore(*This\Barrier1); Open Barrier #1
LockMutex(*This\Mutex)
*This\Counter - 1
If *This\Counter = 0 ; If all Threads have arrived at barrier #2
WaitSemaphore(*This\Barrier1) ; Close Barrier #1
SignalSemaphore(*This\Barrier2) ; Open Barrier #2
EndIf
UnlockMutex(*This\Mutex)
WaitSemaphore(*This\Barrier2) ; Close Barrier #2
SignalSemaphore(*This\Barrier2) ; Open Barrier #2
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
FreeSemaphore(*This\Barrier1)
FreeSemaphore(*This\Barrier2)
FreeMutex(*This\Mutex)
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New(ThreadCount.i)
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\Barrier1 = CreateSemaphore(0)
*This\Barrier2 = CreateSemaphore(1)
*This\Mutex = CreateMutex()
*This\ThreadCount = ThreadCount
*This\Counter = 0
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @Wait()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code generated in : 00.001 seconds (84000.00 lines/second) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CompilerIf #PB_Compiler_IsMainFile
DeclareModule Runner
Interface Runner
GetNumber.i()
GetThreadID.i()
GetCurrentStage.i()
GetBarriers.i()
SetNumber(Number.i)
SetThreadID(ThreadID.i)
SetCurrentStage(CurrentStage.i)
SetBarriers(*Barriers.Barriers::Barriers)
IncrementCurrentStage(Increment.i = 1)
Free()
EndInterface
Declare.i New(Number.i = 0, ThreadID.i = 0, CurrentStage.i = 0, *Barriers.Barriers::Barriers = #Null)
EndDeclareModule
Module Runner
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<
Structure Private_Members
VirtualTable.i
Number.i
ThreadID.i
CurrentStage.i ; Special : Increment
*Barriers.Barriers::Barriers
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The observators <<<<<
Procedure.i GetNumber(*This.Private_Members)
ProcedureReturn *This\Number
EndProcedure
Procedure.i GetThreadID(*This.Private_Members)
ProcedureReturn *This\ThreadID
EndProcedure
Procedure.i GetCurrentStage(*This.Private_Members)
ProcedureReturn *This\CurrentStage
EndProcedure
Procedure.i GetBarriers(*This.Private_Members)
ProcedureReturn *This\Barriers
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The mutators <<<<<
Procedure SetNumber(*This.Private_Members, Number.i)
*This\Number = Number
EndProcedure
Procedure SetThreadID(*This.Private_Members, ThreadID.i)
*This\ThreadID = ThreadID
EndProcedure
Procedure SetCurrentStage(*This.Private_Members, CurrentStage.i)
*This\CurrentStage = CurrentStage
EndProcedure
Procedure SetBarriers(*This.Private_Members, *Barriers.Barriers::Barriers)
*This\Barriers = *Barriers
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Special operator(s) <<<<<
Procedure IncrementCurrentStage(*This.Private_Members, Increment.i = 1)
*This\CurrentStage = *This\CurrentStage + Increment
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New(Number.i = 0, ThreadID.i = 0, CurrentStage.i = 0, *Barriers.Barriers::Barriers = #Null)
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\Number = Number
*This\ThreadID = ThreadID
*This\CurrentStage = CurrentStage
*This\Barriers = *Barriers
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @GetNumber()
Data.i @GetThreadID()
Data.i @GetCurrentStage()
Data.i @GetBarriers()
Data.i @SetNumber()
Data.i @SetThreadID()
Data.i @SetCurrentStage()
Data.i @SetBarriers()
Data.i @IncrementCurrentStage()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
DeclareModule Runners
Interface Runners
CreateThreads()
WaitThreads()
Free()
EndInterface
Declare.i New()
EndDeclareModule
Module Runners
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Constants declaration <<<<<
#RUNNERS_MAX = 10
#STAGE_MAX = 5
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Structure declaration <<<<<
Structure Private_Members
VirtualTable.i
Barriers.Barriers::Barriers
Runners.Runner::Runner[#RUNNERS_MAX]
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The RunnerThread procedure <<<<<
Procedure RunnerThread(*Runner.Runner::Runner)
Debug "Runner " + Str(*Runner\GetNumber()) + " is running !"
Repeat
*Runner\IncrementCurrentStage()
Delay(Random(2000, 500))
Debug "Runner " + Str(*Runner\GetNumber()) + " has arrived on stage " + Str(*Runner\GetCurrentStage()) + " and wait !"
*Barriers.Barriers::Barriers = *Runner\GetBarriers()
*Barriers\Wait()
Debug "Runner " + Str(*Runner\GetNumber()) + " make is critical work !"
Until *Runner\GetCurrentStage() >= #STAGE_MAX
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The CreateThreads operator <<<<<
Procedure CreateThreads(*This.Private_Members)
For RunnersID = 0 To #RUNNERS_MAX - 1
*This\Runners[RunnersID]\SetThreadID(CreateThread(@RunnerThread(), *This\Runners[RunnersID]))
Next
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The WaitThreads operator <<<<<
Procedure WaitThreads(*This.Private_Members)
For RunnersID = 0 To #RUNNERS_MAX - 1
WaitThread(*This\Runners[RunnersID]\GetThreadID())
Next
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Destructor <<<<<
Procedure Free(*This.Private_Members)
If *This\Barriers <> #Null
*This\Barriers\Free()
EndIf
For RunnersID = 0 To #RUNNERS_MAX - 1
If *This\Runners[RunnersID] <> #Null
*This\Runners[RunnersID]\Free()
EndIf
Next
FreeStructure(*This)
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Constructor <<<<<
Procedure.i New()
*This.Private_Members = AllocateStructure(Private_Members)
*This\VirtualTable = ?START_METHODS
*This\Barriers = Barriers::New(#RUNNERS_MAX)
For RunnersID = 0 To #RUNNERS_MAX - 1
*This\Runners[RunnersID] = Runner::New(RunnersID+1, 0, 0, *This\Barriers)
Next
ProcedureReturn *This
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< The Virtual Table Entries <<<<<
DataSection
START_METHODS:
Data.i @CreateThreads()
Data.i @WaitThreads()
Data.i @Free()
END_METHODS:
EndDataSection
EndModule
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
CompilerIf #PB_Compiler_Thread = 0
Debug "Compile this example with the ThreadSafe option activated !"
End
CompilerEndIf
Runners.Runners::Runners = Runners::New()
Runners\CreateThreads()
Runners\WaitThreads()
Runners\Free()
Debug "END OF PROGRAM"
End
CompilerEndIf
; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<