Tasks and threads

Just starting out? Need help? Post your questions and find answers here.
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Tasks and threads

Post by eriansa »

Do you guys think following code can be optimised. It looks ok, but perhaps there are better ways to spread tasks evenly over different threads. I want to implement multi-core support in a real-time audio application.
(surely the delay()'s and so on are only for demonstrational purposes ;-))

Code: Select all

#NrOfThreads=3
#NrOfTasks=50

Structure MyThread
  ThreadId.l
  MutexId.l
  SemaphoreId.l
EndStructure
Global Dim arrThreads.MyThread(#NrOfThreads-1)


OpenConsole()

Procedure MyThread(i) 
  Repeat
  PrintN(" -Waiting Thread->" + Str(i))
  WaitSemaphore(arrThreads(i)\SemaphoreId)
  LockMutex(arrThreads(i)\MutexId)
  PrintN("  -Running Thread->"+str(i))
  For j=1 to 10
    delay(50) 
  Next
  UnlockMutex(arrThreads(i)\Mutexid)
  ForEver 
EndProcedure

For i = 0 to #NrOfThreads-1
  arrThreads(i)\SemaphoreId=CreateSemaphore()
  arrThreads(i)\MutexId=CreateMutex()
  arrThreads(i)\ThreadId=CreateThread(@MyThread(),i)
Next

PrintN("Waiting in Main")
NrOfTasks=#NrOfTasks
delay(500)

Repeat 
  For i= 0 to #NrOfThreads-1
    if NrOfTasks
      if TryLockMutex(arrThreads(i)\MutexId)
        PrintN("Remaining tasks->"+str(NrOfTasks)) 
        NrOfTasks-1 
        UnlockMutex(arrThreads(i)\MutexId)
        PrintN(" -Signalling Thread->"+str(i) )
        SignalSemaphore(arrThreads(i)\SemaphoreId)
        delay(10)
      EndIf
    EndIf
  Next
Until NrOfTasks=0

Printn("All tasks ended, press any key to close")
Repeat
delay(10)
until Inkey()

eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Re: Tasks and threads

Post by eriansa »

Nobody?
cxAlex
User
User
Posts: 88
Joined: Fri Oct 24, 2008 11:29 pm
Location: Austria
Contact:

Re: Tasks and threads

Post by cxAlex »

I think I've coded a Include that can do what you need, a background JobProcessor, with a variable amount of threads, priority management and many other Features. I'm using this Include in many of my projects, it's very stable and fast: Link to german forum and download: http://www.purebasic.fr/german/viewtopic.php?t=19188

Greets, Alex
eriansa
Enthusiast
Enthusiast
Posts: 277
Joined: Wed Mar 17, 2004 12:31 am
Contact:

Re: Tasks and threads

Post by eriansa »

cxAlex wrote:I think I've coded a Include that can do what you need, a background JobProcessor, with a variable amount of threads, priority management and many other Features. I'm using this Include in many of my projects, it's very stable and fast: Link to german forum and download: http://www.purebasic.fr/german/viewtopic.php?t=19188

Greets, Alex
I have implemented your great code into my Audio-app since a couple of months. It works OK, but I am not getting the best performance. (You need to know that my app. works with Asio low latency, with bufferswitches up to 5 ms.)
This results in audio drop-outs.

What I am looking for is the fastest way to spread tasks evenly over the available cores.

If I understand well : PB's Semaphore is Win->WaitFor(Single)(Multiple)Object_/SetEvent_ and PB's Mutex is in fact a Win-> Semaphore.
The question is : are there other implementations possible to speed things up???
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Tasks and threads

Post by Trond »

For latency-sensitive tasks like this I'd keep the threads running as long as the song is playing. With your current implementation they could potentially be put to sleep on the semaphore and then waken up right in the middle of the song again and again, which would lower performance dramatically. Instead leave them spinning in an empty loop when there is no task available. (Maybe leave this as an option - more cpu use and lower latency vs. less cpu and higher latency.)

For distributing the tasks you have two choices, a central queue vs one queue per thread. One queue per thread avoids many threads competing for locking the task queue at the same time, however, distributing the tasks evenly is much harder. You may end up with one cpu overwhelmed and another starving.
Post Reply