TThreadsafeTimer

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

DAK

Betreff: TThreadsafeTimer

BeitragSa, Sep 05, 2009 2:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Da die Timer mit mehreren Threads scheinbar ihre liebe Not haben (seeeehr große prozessorauslastung) hab ich mal schnell eine thread-safe version geschrieben. Hoffe, das kann iwer brauchen.

Habs mal schnell noch gestresstestet: rennt auch mit 50 Threads mit je einem Timer ohne Probleme stabil.

BlitzMax: [AUSKLAPPEN]
Import BRL.Threads
Import BRL.EventQueue

Module DAK.ThreadsafeTimer

Type TThreadsafeTimer
Field LastMS:Int
Field Rate:Int
Field Del:Int
Field Event:TEvent
Field Thread:TThread
Field TimerRunning:TMutex
Field Ticked:Int

Method Stop()
While TryLockMutex(TimerRunning)=False
Wend
WaitThread(Thread)
End Method

Method Ticks:Int()
Return Ticked
End Method

Method Wait:Int()
While Ticked=0
Delay 1
Wend
Local tic:Int = Ticked
AtomicSwap(Ticked,0)
Return tic
End Method

Function Run:Object(in:Object)
Local Timer:TThreadsafeTimer = TThreadsafeTimer(in)
Delay Timer.del
While TryLockMutex(Timer.TimerRunning)
EmitEvent(Timer.Event)
AtomicAdd(Timer.Ticked,1)
UnlockMutex(Timer.TimerRunning)
Delay Timer.del
Wend
Return Null
End Function

Function Create:TThreadsafeTimer(Rate:Int,Event:TEvent=Null)
Local tmp:TThreadsafeTimer = New TThreadsafeTimer
tmp.Rate = Rate
tmp.Del = 1000/Rate
tmp.LastMS = MilliSecs()
If Event<>Null Then
tmp.Event = Event
Else
tmp.Event:TEvent = CreateEvent($801,tmp)
EndIf
tmp.TimerRunning=CreateMutex()
tmp.Thread = CreateThread(TThreadsafeTimer.Run,Object(tmp))
Return tmp
End Function
End Type

Function CreateThreadsafeTimer:TThreadsafeTimer(Rate:Int,Event:TEvent=Null)
Return TThreadsafeTimer.Create(Rate,Event)
End Function

Function WaitThreadsafeTimer:Int(Timer:TThreadsafeTimer)
Return Timer.Wait()
End Function

Function ThreadsafeTimerTicks(Timer:TThreadsafeTimer)
Return Timer.Ticks()
End Function

Function StopThreadsafeTimer(Timer:TThreadsafeTimer)
Timer.Stop()
End Function


hier noch mal n kleiner testcode:

BlitzMax: [AUSKLAPPEN]

SuperStrict
Framework brl.glmax2d
Import brl.threads
Import brl.standardio
Import maxgui.win32maxguiex
Import brl.eventqueue
Import DAK.ThreadsafeTimer

Const NUMBER_OF_THREADS:Byte=3

Global xpos:Int=0
Global xposmutex:TMutex = CreateMutex()

If NUMBER_OF_THREADS>1 Then
Local Thread:TThread[5]

For Local i:Int = 0 To NUMBER_OF_THREADS-2
Thread[i]=CreateThread(TestThread,Null)
DetachThread(Thread[i])
Next
EndIf

TestThread(Null)

Function TestThread:Object(data:Object)
While TryLockMutex(xposmutex)=False
Wend
Local window:TGadget = CreateWindow("Testfenster",xpos,0,200,200,Null,WINDOW_TITLEBAR)
Local id:Int = xpos/200
xpos:+200
UnlockMutex(xposmutex)
Local Endbutton:TGadget
If CurrentThread()=MainThread() Then
Endbutton = CreateButton("END",150,150,40,20,window)
EndIf
Local label:TGadget = CreateLabel("",0,0,200,200,window)
Local count:Int = 0
Local timer:TThreadsafeTimer = TThreadsafeTimer.Create(20)
Print id+" created"
While 1
count:+1
SetGadgetText(label,count)
If CurrentThread()=MainThread() Then
While PollEvent()
If EventID()=EVENT_GADGETACTION And TGadget(EventSource())=Endbutton Then
End
EndIf
Wend
EndIf
timer.wait()
Wend
End Function


viel spaß damit
Gewinner der 6. und der 68. BlitzCodeCompo
  • Zuletzt bearbeitet von DAK am Sa, Sep 05, 2009 13:37, insgesamt einmal bearbeitet

BtbN

BeitragSa, Sep 05, 2009 10:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Du solltest dich lieber nochmal über Mutexes und deren funktionsweise und sinn informieren.
Davon abgesehen ist das Modul alles andere als Thread-Safe, vorallem schon, da es events benutzt.
Und auch hier ist diese sehr seltsame While, TryLock, Wend schleife, da, welche die CPU auf 100% auslastung treibt, und noch dazu an einer sehr seltsamen stelle steht.

DAK

BeitragSa, Sep 05, 2009 13:31
Antworten mit Zitat
Benutzer-Profile anzeigen
was hab ich an mutexes falsch verstanden?... mutexes sind im grunde binarys, die man entweder auf 0 oder 1 setzen kann, oder probieren kann, sie auf 0 zu setzen. wenn man probiert, und die sind schon auf 0, dann liefert das TryLockMutex False zurück... das wars doch, oder?

die events hab cih verwendet um die funktionsweise des originalen timers 1:1 zu imitieren. hast du ne idee, wie ich das machen könnt, ohne events da drin zu verwenden?

warum sind events nicht thread-safe? was ich ausprobiert hab, hats ganz gut geklappt...

die while, trylockmutex, wend - schleife is nur um den timer zu killen.. (das ganze hällt gerade mal einen Timertick lang... und eine 50stel sekunde die cpu auf 100% haben is zwar ned sauber, aber sauberer als der original-timer, der dauerhaft auf 100% is...) das könnt ich aber wohl auch durch n byte, was ich mit atomicadd/swap auf was anderes setz, machen... ich änder das mal...
Gewinner der 6. und der 68. BlitzCodeCompo

BtbN

BeitragSa, Sep 05, 2009 13:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Du könntest auch einfach den Mutex direkt locken, dann warter er automatisch und ohne jegliche CPU-Auslatung, biser ihn locken kann, dafür sind mutexes nämlich gedacht.
Und es gibt keinen weg, die Events thread-safe zu bekommen, und somit auch keinen, den original timer zu imitieren.

DAK

BeitragSa, Sep 05, 2009 13:50
Antworten mit Zitat
Benutzer-Profile anzeigen
das hätt so wie ich den mutex verwendet hab ned geklappt. der mutex wird nämlich vom timer-update schon gelockt, weil mutexe nicht nur ausgelesen werden können, sondern nur mit trylock ausgelesen werden können.. und dann is er schon gelockt... weißt, wie ich mein?

ich habs mal so gelöst:

BlitzMax: [AUSKLAPPEN]

Import BRL.Threads
Import BRL.EventQueue

Module DAK.ThreadsafeTimer

Type TThreadsafeTimer
Field LastMS:Int
Field Rate:Int
Field Del:Int
Field Thread:TThread
Field TimerRunning:Int
Field Ticked:Int

Method Stop()
AtomicSwap(TimerRunning,0)
WaitThread(Thread)
End Method

Method Ticks:Int()
Return Ticked
End Method

Method Wait:Int()
While Ticked=0
Delay 1
Wend
Local tic:Int = Ticked
AtomicSwap(Ticked,0)
Return tic
End Method

Function Run:Object(in:Object)
Local Timer:TThreadsafeTimer = TThreadsafeTimer(in)
Delay Timer.del
While Timer.TimerRunning
AtomicAdd(Timer.Ticked,1)
Delay Timer.del
Wend
Return Null
End Function

Function Create:TThreadsafeTimer(Rate:Int)
Local tmp:TThreadsafeTimer = New TThreadsafeTimer
tmp.Rate = Rate
tmp.Del = 1000/Rate
tmp.LastMS = MilliSecs()
tmp.TimerRunning=1
tmp.Thread = CreateThread(TThreadsafeTimer.Run,Object(tmp))
Return tmp
End Function
End Type

Function CreateThreadsafeTimer:TThreadsafeTimer(Rate:Int)
Return TThreadsafeTimer.Create(Rate)
End Function

Function WaitThreadsafeTimer:Int(Timer:TThreadsafeTimer)
Return Timer.Wait()
End Function

Function ThreadsafeTimerTicks(Timer:TThreadsafeTimer)
Return Timer.Ticks()
End Function

Function StopThreadsafeTimer(Timer:TThreadsafeTimer)
Timer.Stop()
End Function


Is das praktikabel?
Gewinner der 6. und der 68. BlitzCodeCompo

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group