Seite 1 von 2

Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 10:50
von Lowallyn
Hi,

Ich versuche, dass ein erstellter Thread sich exakt alle 100 ms ausführt.
Was ich schon probiert habe:
1:

Code: Alles auswählen

time=ElapsedMilliseconds()
...
...
Delay(100-(ElapsedMilliseconds()-time))
2:

Code: Alles auswählen

time=ElapsedMilliseconds()
...
...
While ElapsedMilliseconds()-time<100
  Delay(0)
Wend
Bei beiden Methoden entstehen aber Schwankungen bis zu 10ms, welche für mich nicht tragbar sind. :(
Hat jemand eine Idee, wie ich das exakter lösen kann?

Danke schonmal für eure Hilfe,
Lowallyn

Re: Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 12:55
von Thorium
Lowallyn hat geschrieben: Bei beiden Methoden entstehen aber Schwankungen bis zu 10ms, welche für mich nicht tragbar sind. :(
Hat jemand eine Idee, wie ich das exakter lösen kann?
Garnicht. Du bist auf einem Multitaskingsystem, Schwankungen sind da unumgänglich.
Also exakt geht schlicht weg nicht. Du kannst es aber genauer machen.

Unter Windows kannst du

Code: Alles auswählen

timeBeginPeriod_(1)
Nutzen um die Systemweite Timerauflösung auf 1ms runterzusetzen.

Ausserdem kannst du zur Zeitmessung QueryPerformanceCounter verwenden und die Threadpriorität erhöhen. Exact wird es dadurch trotzdem nicht.

Aber was genau willst du bezwecken? Vieleicht gibt es eine andere Lösung ohne einen Thread alle 100ms auszuführen.

Re: Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 13:01
von Lowallyn
Erstmal danke für deine Antwort.

Es geht darum, 10mal pro Sekunde den Wert in einer Datei zu ändern,
welche von einem anderen Programm ausgelesen wird.

Parallel läuft ein anderes Programm, welches ebenfalls eine Datei 10mal pro Sekunde modifiziert, welche dann ausgelesen wird.
Auf dieses Programm habe ich keinen Zugriff und will mich deswegen an seine Zeitschritte anpassen.

was ist denn "QueryPerformanceCounter"? Ich finde zu diesem Begriff nichts in der Hilfe.
hast du vlt. einen Beispielcode, welcher mir diese genauere Methode veranschaulichen kann?

Re: Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 15:37
von - chris -
Versuch das mal mit timeGetTime_().

Mit timeGetTime_() hab ich keine Schwankungen,
erst mit ElapsedMilliseconds().

Code: Alles auswählen


For n = 1 To 10

  t1 = timeGetTime_()

  time = timeGetTime_()
  ;time = ElapsedMilliseconds()

  Delay(12)

  Delay(100 - (timeGetTime_() - time)%100)
  ;Delay(100 - (ElapsedMilliseconds() - time)%100)

  t2 = timeGetTime_()  

  time = t2 - t1

  Debug time

Next n


Re: Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 19:20
von PMV
QueryPerformanceCounter und QueryPerformanceFrequenz sind
WinAPI Funktionen genau so wie timeGetTime und timeBeginPeriod/ timeEndPeriod

QueryPerformanceCounter_() wird benötigt, wenn Millisekunden nicht mehr ausreichen.

timeGetTime_() ist nicht auf jedem System gleich aufgelöst, selbes gilt für Delay()
bzw. Sleep_() ... erst durch timeBeginPeriod_()/ timeEndPeriod_() stellt das Windows
entsprechend ein.

MFG PMV

Code: Alles auswählen

timeBeginPeriod_(1)

For n = 1 To 10

  t1 = timeGetTime_()

  time = timeGetTime_()
  ;time = ElapsedMilliseconds()

  Delay(12)

  Delay(100 - (timeGetTime_() - time)%100)
  ;Delay(100 - (ElapsedMilliseconds() - time)%100)

  t2 = timeGetTime_()  

  time = t2 - t1

  Debug time

Next n

timeEndPeriod_(1)

Re: Thread exakt regelmäßig ausführen

Verfasst: 13.09.2011 19:25
von NicTheQuick
Gibt es für sowas nicht Timer? Dazu gibt es doch schon einige Threads hier im Forum.

Re: Thread exakt regelmäßig ausführen

Verfasst: 14.09.2011 08:51
von Lowallyn
Hmm, dann habe ich wohl ein Problem mit all diesen Funktionen.
Ich verwende momentan nämlich noch die Demo und habe dementsprechend keine API.

Mein Bruder hat gesagt, dass ich die DLLs einbinden könnte, um das zu umgehen.
könnt ihr mir das erklären?

Danke schonmal für die reichlichen Antworten (Ich hoffe auf mehr ;) ),
Lowallyn

Re: Thread exakt regelmäßig ausführen

Verfasst: 14.09.2011 09:44
von c4s
@NicTheQuick
Meinst du die Window-Timer? Die sind relativ ungenau, da sie mit geringer Priorität laufen.

Lowallyn hat geschrieben:Mein Bruder (Macros) hat gesagt, dass ich die DLLs einbinden könnte, um das zu umgehen.
könnt ihr mir das erklären?
Nein. Hier wird nicht erklärt, wie man die Demo-Beschränkung umgeht. Entweder selber herausfinden oder es lieber gleich sein lassen und die Vollversion kaufen.

Re: Thread exakt regelmäßig ausführen

Verfasst: 14.09.2011 17:04
von - chris -
So gehts mit einbinden der DLL:

Code: Alles auswählen


;http://msdn.microsoft.com/en-us/library/dd757629(v=vs.85).aspx

Prototype.i timeGetTime()

Winmm_hDLL = OpenLibrary(#PB_Any, "Winmm.dll")

If Winmm_hDLL = 0
  End
EndIf

Global timeGetTime.timeGetTime = GetFunction(Winmm_hDLL, "timeGetTime")


For n = 1 To 10

  t1 = timeGetTime()

  time = timeGetTime()
  ;time = ElapsedMilliseconds()

  Delay(12)

  Delay(100 - (timeGetTime() - time)%100)
  ;Delay(100 - (ElapsedMilliseconds() - time)%100)

  t2 = timeGetTime() 

  time = t2 - t1

  Debug time

Next n


If Winmm_hDLL
  CloseLibrary(Winmm_hDLL)
EndIf

End


Re: Thread exakt regelmäßig ausführen

Verfasst: 14.09.2011 17:20
von NicTheQuick
Hier mal meine Variante, die bei mir super läuft

Code: Alles auswählen

Procedure Do()
	Static count.i = 0
	Debug Str(count) + ": " + Str(ElapsedMilliseconds())
	count + 1
EndProcedure

Structure TimerThread
	diffTime.i
	quit.i
	hThread.i
EndStructure

Procedure TimerThread(*info.TimerThread)
	Protected time.i = ElapsedMilliseconds() + *info\diffTime
	
	While Not *info\quit
		Do()
		While (time > ElapsedMilliseconds())
			Delay(1)
		Wend
		time + *info\diffTime
	Wend
	
	FreeMemory(*info)
EndProcedure

Procedure.i StartTimer(diffTime.i)
	Protected *info.TimerThread = AllocateMemory(SizeOf(TimerThread))
	
	If *info
		*info\diffTime = diffTime
		*info\quit = #False
		
		*info\hThread = CreateThread(@TimerThread(), *info)
		
		ProcedureReturn *info
	EndIf
	
	ProcedureReturn #False
EndProcedure

Procedure StopTimer(*info.TimerThread)
	*info\quit = #True
	
	WaitThread(*info\hThread)
EndProcedure

Define *timer = StartTimer(50)

Delay(2000)
StopTimer(*timer)
Debug "End"
In der Procedure 'Do()' kommen dann die Sachen 'rein, die alle x ms getan werden sollen.
Dazu noch der Debuggeroutput:
0: 865
1: 915
2: 965
3: 1015
4: 1065
5: 1115
6: 1165
7: 1216
8: 1265
9: 1315
10: 1365
11: 1415
12: 1465
13: 1515
14: 1565
15: 1615
16: 1665
17: 1715
18: 1765
19: 1815
20: 1865
21: 1915
22: 1965
23: 2015
24: 2065
25: 2115
26: 2165
27: 2215
28: 2265
29: 2316
30: 2366
31: 2415
32: 2465
33: 2515
34: 2565
35: 2615
36: 2665
37: 2715
38: 2765
39: 2815
End