Code archives/Miscellaneous/WorkingQueue
This code has been declared by its author to be Public Domain code.
Download source code
| A Threadool creates a defined number of Threads. These Threads do not die after their work is done, so there is no syscall overhead when they are needed again. They rest in a pool, used simply when they are needed and some work has to be done. The work is organised in so called "Tasks" You can create 1000's of different Tasks, and add them to an Workingqueue - The queue is simply First in - First out. The queue simply looks for unused threads in its threadspool, and assigns them some work. |
SuperStrict ' *** THREADPOOL CLASSES START *** Type TWorkQueue Field nThreads:Int Field threads:TThread[] Field queue:TList Field mut_List:Int Function Create:TWorkQueue(nThreads:Int = 10) Local t:TWorkQueue = New TWorkQueue t.nThreads = nThreads t.threads = New TThread[nThreads] t.queue = New TList t.mut_List = CreateMutex() For Local i:Int = 0 To nThreads-1 t.threads[i] = TThread.Create( QueueWrapper, Object(t) ) Next Return t EndFunction Function QueueWrapper:Object( data:Object) Local myTask:TWorkQueue = TWorkQueue(data) myTask.Execute() EndFunction Method AddTask(obj:TTask) LockMutex(mut_List) queue.AddLast(obj) UnlockMutex(mut_List) EndMethod Method DoWork:Int() If Not queue.IsEmpty() LockMutex(mut_List) Local t:TTask = TTask(queue.First()) UnlockMutex(mut_List) Local i:Int = 0 While i < nThreads If threads[i].GetStatus() = False threads[i].SetFunction(t.func, t.data) LockMutex(mut_List) queue.RemoveFirst UnlockMutex(mut_List) threads[i].Start() Exit Else i :+ 1 EndIf Wend Return True Else Return False EndIf EndMethod Method Execute() ' Dummy EndMethod EndType Type TTask Field func:Object( data:Object ) Field data:Object Method Run() If func Then func(data) EndMethod Function Create:TTask(func:Object( data:Object ), data:Object ) Local t:TTask = New TTask t.func = func t.data = data Return t EndFunction EndType Type TThread Field id:Int Field mutex:Int Field func:Object( data:Object ) Field data:Object Field working:Int Function Create:TThread(func:Object( data:Object ), data:Object) Local t:TThread = New TThread t.id = CreateThread( ThreadWrapper, Object(t) ) t.mutex = CreateMutex() t.func = func t.data = data t.working = False LockMutex(t.mutex) Return t EndFunction Function ThreadWrapper:Object( data:Object) Local myTask:TThread = TThread(data) myTask.Execute() EndFunction Method SetFunction(func:Object( data:Object ), data:Object) Self.func = func Self.data = data Self.working = False EndMethod Method GetStatus:Int() Return working EndMethod Method Destroy() DetachThread(id) id = 0 CloseMutex(mutex) mutex = 0 working = False func = Null data = Null EndMethod Method Execute() Repeat If Self.working = True working = Self.DoWork() EndIf If Self.working = False LockMutex(mutex) EndIf Forever EndMethod Method DoWork:Int() If func Then func(data) Return False EndMethod Method Start() UnlockMutex(mutex) Self.working = True EndMethod Method Suspend() Self.working = False EndMethod EndType ' *** THREADPOOL CLASSES END *** ' ***** EXAMPLE START **** ' Demo Functions, just generate some heavy Workload :) Function fTest1:Object(data:Object) Local superCalcResult:Double For Local x:Int = 0 To 1000000 superCalcResult = x*Cos(x)+Tan(x)*x/x Next EndFunction Function fTest2:Object(data:Object) Local superCalcResult:Double For Local x:Int = 0 To 1000000 superCalcResult = x*Cos(x)+Tan(x)*x/x Next EndFunction 'Create a WorkQueue with 8 preinitalised Threads waiting for work Local q:TWorkQueue = TWorkQueue.Create(8) 'Create a LOT of Tasks to be done Local test1:TTask[] = New TTask[200] Local test2:TTask[] = New TTask[200] 'Assign the Functions you want to be done to the Tasks 'I'm pretty lazy - using, just the same functions :) For Local i:Int = 0 To 199 test1[i] = TTask.Create(fTest1, String(i)) test2[i] = TTask.Create(fTest2, String(i)) Next Print "Initialized..." ' To prove that ther is no CPU time wasted with 8 Threads waiting for work (look at the Taskmanager) Delay 1000 Print "Starting..." 'Assign the 400 Tasks to the WorkQeue For Local i:Int = 0 To 199 q.AddTask(test1[i]) q.AddTask(test2[i]) Next Local starttime:Int = MilliSecs() While Not KeyHit(KEY_ESCAPE) 'Update the WorkQueue If Not q.DoWork() Exit 'Print q.queue.Count() 'it should also be possible to but this loop in an extra thread, maybe in future :) Wend Print "Duration "+String(MilliSecs()-starttime)+" ms" |