Thread (encore une fois) et interruption
Publié : dim. 29/juil./2012 0:27
Bonjour,
venant du monde Motorola 68000 (pour les plus jeune, non ce n'est pas un téléphone
) je voyais la gestion des threads Purebasic plus rigoureuse... je m'explique :
Pour mon programme domotique, je scanne un port (série ou réseau). Les commandes domotique fonctionnent comme le protocole UDP : donc quand je veut connaitre l'état d'un capteur, je demande à ce capteur de me m'envoyer la réponse (SEND) et je dois ensuite attendre une réponse.
Pour me simplifier la vie (car il y a de nombreux messages), j'ai décidé d'utiliser un thread pour lire les messages entrants (LectureNet) qui stocke les messages dans une liste chainée (GLOBALE et utilisation des MUTEX bien sûr)
Mais si ailleurs dans mon programme j'attend une valeur ou si je créé une 'pause' par DELAY(3000) ou REPEAT...UNTIL ElapsedTime()-t>TIMEOUT, le thread semble bloqué lui aussi... je ne suis pas certain (à cause du mode de transmission type UDP du BUS) mais j'ai des latences de plusieurs secondes là où le BUS ne tolère pas plus de 500 ms environ.
Le listing est trop long pour apparaître ici et de plus il manque l'accès lecture à un port réseau mais je souhaite vraiment comprendre le fonctionnement des threads !!!
N'est-ce pas lié à une interruption par exemple ? est-ce vraiment régulier ? le buffer réseau du PC peut-il apporter cette latence (NetworkClientEvent()) ?
Bref, je suis un peu limité et mes debug str(elapsedtime())+": je fais-ci ou ça" ne m'aident plus suffisamment...
Je joins quand même quelques extraits de mon code (et je compile en X86/Thread safe)
venant du monde Motorola 68000 (pour les plus jeune, non ce n'est pas un téléphone

Pour mon programme domotique, je scanne un port (série ou réseau). Les commandes domotique fonctionnent comme le protocole UDP : donc quand je veut connaitre l'état d'un capteur, je demande à ce capteur de me m'envoyer la réponse (SEND) et je dois ensuite attendre une réponse.
Pour me simplifier la vie (car il y a de nombreux messages), j'ai décidé d'utiliser un thread pour lire les messages entrants (LectureNet) qui stocke les messages dans une liste chainée (GLOBALE et utilisation des MUTEX bien sûr)
Mais si ailleurs dans mon programme j'attend une valeur ou si je créé une 'pause' par DELAY(3000) ou REPEAT...UNTIL ElapsedTime()-t>TIMEOUT, le thread semble bloqué lui aussi... je ne suis pas certain (à cause du mode de transmission type UDP du BUS) mais j'ai des latences de plusieurs secondes là où le BUS ne tolère pas plus de 500 ms environ.
Le listing est trop long pour apparaître ici et de plus il manque l'accès lecture à un port réseau mais je souhaite vraiment comprendre le fonctionnement des threads !!!
N'est-ce pas lié à une interruption par exemple ? est-ce vraiment régulier ? le buffer réseau du PC peut-il apporter cette latence (NetworkClientEvent()) ?
Bref, je suis un peu limité et mes debug str(elapsedtime())+": je fais-ci ou ça" ne m'aident plus suffisamment...

Je joins quand même quelques extraits de mon code (et je compile en X86/Thread safe)
Code : Tout sélectionner
th= CreateThread(@ReadBUS(),0) ; ReadBUS contient une boucle sur LectureNet()
...
Procedure.d GetImmediatTemp(Amodule.s)
If Val(Amodule.s) > 0 And Val(Amodule.s) < 255
d = ElapsedMilliseconds()
If Left(Amodule.s,1)="$"
Amodule.s = Right(Amodule.s, Len(Amodule.s)-1)
EndIf
time.i = Date()
Debug Str(ElapsedMilliseconds())+" : AskTempSensor start"
AskTempSensor(*BufOut, Val("$"+Amodule.s))
Debug Str(ElapsedMilliseconds())+" : AskTempSensor end"
Repeat
oldvalue = ListSize(BusCommand())
Repeat
LectureNet()
Until ListSize(BusCommand()) <> oldvalue
Debug "recherche..."
temp.d = SearchTemp(Amodule.s, time.i-5)
AskTempSensor(*BufOut, Val("$"+Amodule.s))
Until temp.d > -274
Debug Str(ElapsedMilliseconds()-d)+" : end (DELTA)"
Debug "-------------"
ProcedureReturn temp.d
EndIf
ProcedureReturn -275
EndProcedure
...
...
Procedure.i LectureNet()
; Read Network buffer and if data are present, convert them in hexa string (human readable)
If NetworkClientEvent(ConnectionID) = #PB_NetworkEvent_Data ; only if data are available !
d = ElapsedMilliseconds() ; Prepare watchdog
Resultat = ReceiveNetworkData(ConnectionID, *Buffer, #VBUS_Buffer) ; Read data
If ElapsedMilliseconds()-d > #VBUS_TimeOut ; Check Timeout
VelbusErrorAlert("Warning","No Network response "+Str(Resultat)+" byte.", "Timeout "+Str(ElapsedMilliseconds()-d)+"ms.")
RestartVelbusServer(1)
EndIf
StatusBarText(#BarreEtat,2,FormatDate("%dd/%mm/%yyyy %hh:%ii:%ss",Date()))
If Resultat ; All is OK, Then...
VelbusDebit(60) = VelbusDebit(60) + Resultat ; prepare bandwith monitor
cpt = 1 ; that's watchdog counter
While (Resultat > #VBUS_Buffer-2 And cpt < 22) ; Is there a saturation ?
Resultat = ReceiveNetworkData(ConnectionID, *Buffer, #VBUS_Buffer); then try to clean buffer
Commande$ = Hexa2(*Buffer, Resultat)
Debug "Overflow ("+Str(cpt)+" time) ----------- > "+commande$
cpt = cpt + 1
Wend
If cpt > 1
VelbusErrorAlert("Warning","Network buffer overflow "+Str(cpt-1)+" time.",Commande$)
EndIf
If cpt > 20
RestartVelbusServer(1)
EndIf
Commande$ = Hexa2(*Buffer, Resultat) ; Convert byte in ASCII readable
position.i = ListIndex(BusCommand())
compte = AnalyseMessage(Commande$)
If compte > 0
SelectElement(BusCommand(),position.i+1) ; position précédente, pour afficher nouveaux messages
Repeat
Select Mid(BusCommand()\BusCmd, 9, 2)
Case "D9","DA"
comment$="Error "
Case "E5", "E6"
;comment$ = "Temp "
Debug Str(ElapsedMilliseconds())+" : VBUS msg = "+BusCommand()\BusCmd
Case "00"
comment$ = "Push "
Case "FB", "01", "02", "03"
comment$ = "Relay "
Case "F4", "F5", "F6", "F7", "F8", "F9"
comment$ = "LED "
Case "0F"
comment$ = "Dimme "
Case "FF"
comment$ = "ScanR "
Case "F0", "F1", "F2"
comment$ = "Label "
;Debug BusCommand()\BusCmd
Default
comment$ = "--?-- "
EndSelect
If comment$ <> ""
R = AddGadgetItem(#Logs, 0, FormatDate("%dd/%mm/%yy %hh:%ii:%ss",Date())+" <-- "+comment$+" "+BusCommand()\BusCmd)
EndIf
a = NextElement(BusCommand())
Until a = 0
Else
Debug "lost message"
EndIf
StatusBarText(#BarreEtat,2,Str(ListSize(BusCommand()))+" Messages")
ProcedureReturn(Compte)
EndIf
ProcedureReturn -1
EndIf
EndProcedure