Page 1 sur 3

Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 0:27
par Golfy
Bonjour,

venant du monde Motorola 68000 (pour les plus jeune, non ce n'est pas un téléphone :lol: ) 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)

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


Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 0:44
par Backup
si tu veux quelque chose de "regulier" ; utilise les Timers !

tu peux te servir d'un timer pour lancer un thread ;)


oublie les Delay() qui ne sont pas du tout fait pour ça

delay() met en pause ton prg ( et rend la main au systeme d'exploitation )

ps: les Threads ne sont pas regulier !
seul les timers le sont ....

un timer peut eventuellement servir de Gachette pour un thread ....

un thread est une procedure qui sera appelé de façon Assynchrone
la fin du thread peut differer ... et ne pas se terminer toujours avec le meme temps
le debut d'un thread peut ne pas commencer toujours au meme moment


si tu veux faire un algo qui soit synchronisé a un Top
les timers sont la reponse ;)

Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 12:14
par Golfy
Merci pour ta réponse Dobro :)

J'utilise déjà des timers pour vider la file d'attente (liste chainée) des évènements trop vieux.
Le problème semble être que Purebasic exécute les procédures jusqu'au bout avant de pouvoir traiter autre chose : si je suis dans une procédure de scan des modules domotique (qui me prend 2 mn), même si le timer s'active, il ne sera traité qu'à partir du moment ou il y a un WindowEvent()... et si je met ce WindowEvent() dans toutes mes procédures, est-ce propre ? comment va se dérouler mon programme s'il y a un clic qui envoit sur une autre procédure longue ?

Du coup, la solution d'un thread de lecture permanente du bus Velbus pour alimenter ma pile et des procédures de recherche pour trouver les évènements qui m'intéressent (appui interrupteur, activation relais, état température, etc.) me paraît la seule option propre... sauf si ça ne marche pas :roll:

En plus pour les timer, la doc dit :
Note: Les évènements minuteur ne seront générés que si aucun autres évènements ne doivent être processés (les minuteurs ont une priorité basse). Cela implique qu'ils sont relativement peu précis, et que la durée entre deux évènements du même minuteur peut varier. Ils n'ont pas pour vocation à être utilisé pour de la précision, mais plutôt pour effectuer des tâches périodiques comme par exemple la mise à jour d'un gadget.
Par contre un delay(5) permet de libérer l'utilisation du processeur (mes évènements sont de l'ordre de 100-500ms) et donc éviter 25% d'occupation CPU juste pour la boucle de scan.

Teo & Tea --> http://sourceforge.net/projects/teotea/files/Sources/

Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 18:39
par Backup
la doc sur le timer concerne la version Purebasic !

je pense que pour la version API window c'est different : regarde :

dans le code suivant, je fait sonner un beep toute les secondes ... amuse toi a bouger la fenetre dans tout les sens ou a changer sa taille (en bas a droite) (c'est a dire a générer des événements)
cela ne perturbe pas la régularité du beep (1 par seconde ) ;)


Code : Tout sélectionner

Declare TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)

Enumeration
	#timer_1
	#timer_2
	#timer_3
EndEnumeration

If OpenWindow(0, 100, 100, 100, 100,"", #PB_Window_SystemMenu|#PB_Window_SizeGadget)
	Handle = WindowID(0)
	
	SetTimer_(Handle, #timer_1, 1000, @TimerProc()) ; envoie un evenement toutes les 1000 millisecondes ; en fait on prepare un timer qui enverra cette evenement
	SetTimer_(Handle, #timer_2, 200, @TimerProc())  ; envoie un evenement toutes les 200 millisecondes ; en fait on prepare un timer qui enverra cette evenement
	SetTimer_(Handle, #timer_3, 3000, @TimerProc())  ; envoie un evenement toutes les 3000 millisecondes ; en fait on prepare un timer qui enverra cette evenement
	
	Repeat
	Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf 



; cette procedure contient les actions a effectuer des  3 timers
Procedure TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
	Select uMsg
		Case #WM_TIMER
		Select idEvent
			Case  #timer_1
			Debug "--------------------1 seconde"
			; Ici, le code à executer toutes les secondes
			beep_(440,100)
			Case  #timer_2
			Debug "0.2 secondes"
			; Ici, le code à executer toutes les 200 millisecondes
			Case #timer_3
			Debug "-------------------------------------------3 secondes"
			
			; Ici, le code à executer toutes les 3 secondes
		EndSelect
	EndSelect
EndProcedure
; EPB



Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 18:57
par GallyHC
Bonjour,

Je me suis fait y a quelque temps de cela une petite procedure Wait() car la fonction Delay(), bloque d'execution du programme. Voila la procedure.

Code : Tout sélectionner

Procedure Wait(lwait.l = 0)
; VERIFICATION D'UNE CONNEXION AU RESEAU.
  Define event.l
  Define bproend.b = #False
  Define endtime.l = lwait * 1000
  Define curtime.l = ElapsedMilliseconds()

  Repeat
    event = WaitWindowEvent(50)
    If ElapsedMilliseconds() - curtime > endtime
      bproend = #True
    EndIf
  Until bproend = #True

EndProcedure
Codialement,
GallyHC

Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 21:16
par Golfy
on ne peut pas faire ça (plus court et simple) ?

Code : Tout sélectionner

Procedure Wait(lwait.l = 0)     ; Pourquoi la variable est mise à zéro ?
; VERIFICATION D'UNE CONNEXION AU RESEAU.
  Define event.l
  Define curtime.l = ElapsedMilliseconds()
  Repeat
    event = WaitWindowEvent(50)
  Until ElapsedMilliseconds() - curtime > lwait
EndProcedure
D'autre part, le scan des évènements n'est-il pas nuisible si on ne les traites pas ?
WaitWindowEvent() ne peut être appelé qu'une seule fois par boucle d'évènements, sinon les évènements seront "perdus" (chaque événement ne peut être traité qu'une seule fois et n'est plus disponible pour un deuxième traitement).
J'aimerai vraiment que Fred explique le mode de fonctionnement du multitâche (threads, timers et des events) :|
vous croyez que je peux le contacter par email ?

Re: Thread (encore une fois) et interruption

Publié : dim. 29/juil./2012 23:32
par Backup
voila comment que je comprends la chose :

les events sont une liste d'evenements qui sont crees par un prg
par exemple ( redimensionnement d'une fenetre , clique boutons souris , click sur un gadget etc ... )

les Threads : un thread est une procédure qui va se lancer de façon asynchrone
mais qui reste lié a ton prg

asynchrone veux dire que cette procédure va se dérouler en "parallèle" du prg principale sans etre synchronisé a lui
donc , le retour ( la fin ) du thread n'est pas prévisible ... mais son debut si !
et l'action de cette procédure va se faire alors que le prg principale continue son travail ( d'ou l'impression de parallélisme )

un thread est donc une sorte de traitement parallèle mais temporaire .. a la fin du traitement, le thread s’arrête ..
ideal pour un traitement qui ne demande pas que l'utilisateur surveille ce qui se passe
un encodage/décodage par exemple
ideal pour un traitement anecdotique ..temporaire


les timers
, c'est une procédure qui va s'effectuer de façon synchrone a une horloge (synchrone au système d'exploitation)
mais pas par rapport a ton prg ! (elle sera donc aussi tout comme un thread, , asynchrone, par rapport a ton prg)

du coup on a bien une régularité , mais par rapport a l'horloge du système ....:)

cette procédure va donner une impression de parallélisme , car elle va aussi s’exécuter en même temps que le prg qui l'a lancé mais ....
elle sera cadencée par le système , et du coup ne tiendra pas compte de ton prg

cette procédure sera un rail ! qui ne dévira pas de l'horloge système !! bien plus régulier que les threads
du coup elle deviens bien plus parallèle qu'un thread !
puisqu'en plus elle se répète a l'infini si on le désire ..

un peu comme si nous avions un 2em prg qui tourne de façon continu, en arrière plan

bien sur , il ne faut pas que le traitement a faire faire par le timer , soit plus long que sa fréquence , sinon ça va etre le cirque ...

un timer sera hyper régulier si le temp de traitement reste inferieur a la periode de répétition ....

si tu lance un timer par seconde , et que le traitement de la procedure dure plus d'une seconde
un deuxieme traitement sera lancé alors meme que le premier n'est pas fini .....
Faut tenir compte de ça dans le choix de la frequence de répétition du timer ....



un timer peut etre démarré une seul fois .... , exécuter un traitement, et etre arreté a la fin de ce traitement ! (voir exemple plus bas..qui arrete le traitement mais pas le timer..)
un timer peut aussi s'arreter ! voir KillTimer_()

un timer c'est comme un ordre de mise a feux (une gachette) qui serai proposé par le systeme d'exploitation
on peut aussi se servir de la périodicité d'un timer pour faire effectuer une tache réguliere

réguliere par rapport au systeme d'exploitation

( un peu le systeme des interruptions sous Atari ) ;)


voici encore un exemple de timer adapté au sprite :
ici je me sert du timer comme gachette de debut de traitement
une impulsion par seconde et comme il se trouve que la balle met moins d'une seconde pour traverser l'ecran, c'est bon :)
le traitement sera donc fini AVANT qu'un autre ordre de mise a feu soit donné par le timer ... OUF !

change la valeur du timer pour qu'au lieu d'etre activé chaque seconde , il le soit chaque 250 em de seconde
et regarde ce qui se passe
(remplace ligne 38 :

Code : Tout sélectionner

SetTimer_(Handle, #timer_1, 1000, @TimerProc())
par

Code : Tout sélectionner

SetTimer_(Handle, #timer_1, 250, @TimerProc())
lorsque tu aura mis 250 le timer ne pourra pas finir son traitement, que deja un autre "Start" arrive !
du coup ça désynchronise le binz's .. chez moi apres le 3em tir , il est en carafe !!

ceci est la preuve qu'il faut que le traitement (symbolisé ici par la course de notre sprite) soit plus court
que la periode (fréquence) du timer :)

cet exemple te montre aussi comment utiliser un timer qu'un certain nombre de fois ... ici il va lancer 10 fois le sprite pas plus ! ;)

Code : Tout sélectionner

If compteur_de_tir>10
l'exemple:

Code : Tout sélectionner

Declare TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)

Enumeration
	#Window
	#timer_1
	#timer_2
	#timer_3
	#ball
EndEnumeration

Structure ball
	x.l
	y.l 
	sensy.l
EndStructure
Dim ball.ball(1)
ball(1)\x =1024/2
ball(1)\y=768
ball(1)\sensy.l=-16
Global gachette.b,compteur_de_tir


InitSprite():InitKeyboard()


If OpenWindow(#Window, 100, 100, 1024, 768,"", #PB_Window_SystemMenu)
	OpenWindowedScreen(WindowID(#Window),10,10,1024,768,1,1,1) 
	; ********** creation du sprite ********************
	CreateSprite(#ball,32,32)
	StartDrawing(SpriteOutput(#ball))
		Circle(16,16,16,RGB(255,255,0))
	StopDrawing()
	; **********************************************
	DisplaySprite(#ball,ball(1)\x,ball(1)\y)
	FlipBuffers()
	
	Handle = WindowID(#Window) 
	SetTimer_(Handle, #timer_1, 1000, @TimerProc()) ; envoie un evenement toutes les 1000 millisecondes (1 seconde) ; en fait on prepare un timer qui enverra cette evenement 
	; *********** boucle principale ******************************************
	Repeat 
		Event=WindowEvent()  
		ExamineKeyboard()
		If compteur_de_tir>10
			beep_(50,100)
			gachette.b=0 ; on a arreté le tir parceque le compteur est superieur a 10
			; mais le timer tourne toujours ..... ;o) 
		EndIf
		
		If gachette.b=1   ; le timer a declenché la gachette 
			
			
			ball(1)\y=ball(1)\y+ball(1)\sensy.l 
			If  ball(1)\y<0
				ball(1)\y=768
				gachette.b=0 ; la balle est arrivé en haut on la remet a sa place, et la gachette reviens a sa place
			EndIf 
			Else
			ball(1)\y=768  
			gachette.b=0 ; on remet la gachette a zero pour le prochain timer
			
		EndIf
		
		
		
		;  CallDebugger
		DisplaySprite(#ball,ball(1)\x,ball(1)\y)
		FlipBuffers()
		ClearScreen(RGB(0,0,0))
		
	Until KeyboardPushed(#PB_Key_Escape) Or Event=#PB_Event_CloseWindow
	; **********************************************************************
EndIf 



; cette procedure contient les actions a effectuer par le timer
Procedure TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
	Select uMsg
		Case #WM_TIMER
		Select idEvent
			Case  #timer_1 ; on va se servir du timer comme gachette de tir !!
			Debug "--------------------1 seconde"
			; Ici, le code à executer toutes les secondes 
			compteur_de_tir=compteur_de_tir+1 ; on incrmente le nombre de tir , pour pouvoir l'arreter
			gachette.b=1
		EndSelect
	EndSelect
EndProcedure
; EPB


Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 10:23
par Golfy
Merci encore Dobro pour ta patience et ta pédagogie (que j'apprécie régulièrement sur les posts du forum au passage :wink: )

C'est bien comme cela que je voyais les choses : un thread alimente en permanence ma liste chainée avec les messages reçus du BUS de manière asynchrone (pas de timer possible ou alors < 50ms).
Voici la schématique retenue :

Image

Le problème est que depuis que j'ai transformé mon code pour devenir "threadé", la procédure (C) envoit une demande de température et le thread (A) n'enregistre le message correspondant que 3 à 6 secondes après ! avant, c'était plus rapide (<500 ms).

Si je ne mets pas de delay(), le programme occupe 25% de CPU (inutilement car peu de message domotique)
Si je mets un delay(5), je rend la main au système y compris pour le thread (quelle est la garantie que le système rende la main à mon programme rapidement ?)
Si je mets un timer, je risque parfois de saturer le buffer réseau (pour chaque bouton appuyé, il y a 6 messages de 14 octets environ... mais largement plus lorsque c'est un ordre pour plusieurs modules (volets par exemple) à 16,6kbps)

Bon, je continue à chercher une erreur ou une mauvaise interaction (non-prévue) mais le débug à ce niveau est difficile :(
En plus, maintenant je n'ose même plus dire que je suis débutant en Purebasic :oops: :lol:

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 10:55
par Backup
Golfy a écrit : Le problème est que depuis que j'ai transformé mon code pour devenir "threadé", la procédure (C) envoit une demande de température et le thread (A) n'enregistre le message correspondant que 3 à 6 secondes après ! avant, c'était plus rapide (<500 ms).
ma question va etre , pourquoi avoir separé dans 2 procédures différentes la demande d'info , et la récupération d'info ??

perso j'aurai regroupé dans la meme procedure (le meme thread)

la demande d'info , et la récupération de cette info , de sorte de quitter le thread lorsque l'info est recuperée !

enfin ce que j'en dis :)

pour moi ton problème viens de là !

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 10:57
par djes
Normalement, ton programme ne doit se réveiller que s'il arrive quelque chose sur le réseau. Il ne faut pas faire de boucle avec des delay(), ni du polling (rechercher sans arrêt), ça c'est l'OS qui le gère, en bas niveau. Et à mon avis tu ne devrais pas utiliser l'UDP mais le TCP qui seul permet d'être sûr que les paquets sont bien arrivés/réceptionnés (vu le délai, ça ne devrait pas poser de problème). Les threads sont très bien pour ce genre de problèmatique, même si parfois on galère un peu à comprendre le mécanisme...

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 11:22
par Golfy
*Arf* c'est le principe du bus CAN :roll:
Il n'est pas "temps réel" et fonctionne selon un principe équivalent à UDP (Djes --> ce n'est pas UDP puisque coté bus c'est le protocole CAN, et entre le serveur et le PC c'est bien TCP que j'utilise)

La séparation de la lecture des messages (A) et de l'envoi est que suis amené à recevoir de nombreux messages (et pas seulement le retour de ma demande). [EDIT] j'utilise le même principe que les évènements Windows que je gère avec WindowEvent() !
Mon objectif est par la suite de créer des procédures pour traiter (dépiler) chaque message reçu (et parfois des messages ne sont pas générés par mon programme mais par les interrupteurs de la maison ou les capteurs).
Je pourrais ensuite grapher le temps d'allumage d'une lampe par exemple, comme ce que j'ai déjà fait ici :
http://golfy.free.fr/Velbus/index.html

La page est créée et générée par mon programme en Purebasic (et transférée par un FTP de mon cru... en Purebasic) :D

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 12:31
par Backup
Golfy a écrit : La séparation de la lecture des messages (A) et de l'envoi est que suis amené à recevoir de nombreux messages (et pas seulement le retour de ma demande).
oui ben pourquoi ne pas faire des procedures "utilisateur" dédiées aux Demandes de l' utilisateur , donc des procedures spécifiques ..qui répondent a un besoin précis , Thréadé.. si tu veux qui attendent une réponse .. donc en dehors de la liste des evenement (réponse au coup par coup 1 appel=1 réponse... donc pas d'inscription dans la liste)

et une procedure "system" qui serait elle, éventuellement appelé de façon reguliere (Timer ? avec uns frequence superieur au plus grand evenement..voir plus haut )
pour que cette procedure spécifique remplisse une liste chainée des évenement system d'informations

liste d'evenements qui seront traités de façon sequentiel par ton prg ( affichage des lumieres,alarme,porte .. et dieu sait quoi :)

au passage le traitement de la liste peux aussi etre effectué par cette procedure ....
par un system de filtre d'information , il est assez simple de faire réagir une procedure en fonction d'un element de liste

ton probleme est clairement un probleme d'architecture de code je pense :)
le fait de tout centraliser sur la meme liste (demande "utilisateur" et message "system"), n'est pas judicieux ....

mais je ne connais pas Velbus ...

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 12:47
par djes
Dis donc, tu produis bien là ;)

J'ai vu passer une version modifiée de l'atomic web server avec la gestion des threads... Mais je crois qu'il y a eu mieux depuis !
Sinon, je ne comprends pas ta façon d'utiliser ReceiveNetworkData(). Normalement tu dois lire tout ce qu'il y a de disponible, et après seulement traiter le résultat...

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 14:09
par Golfy
djes a écrit : Sinon, je ne comprends pas ta façon d'utiliser ReceiveNetworkData(). Normalement tu dois lire tout ce qu'il y a de disponible, et après seulement traiter le résultat...
Le traitement dans cette procédure de lecture est uniquement pour debug/stats pour le moment (j'ai rencontré beaucoup de problème dûs... à des erreurs de ma part sur les longueur de buffer) mais comme le suggère Dobro, peut-être vais-je créer plusieurs files d'attentes séparées, d'où l'idée du "Select Case".

Bizarrement, lorsque NetworkClientEvent(x) signale des données présentes, les messages Velbus sont toujours entiers (les trames ne sont pas tronquées).
dobro a écrit :oui ben pourquoi ne pas faire des procedures "utilisateur" dédiées aux Demandes de l' utilisateur , donc des procedures spécifiques ..qui répondent a un besoin précis , Thréadé.. si tu veux qui attendent une réponse .. donc en dehors de la liste des evenement (réponse au coup par coup 1 appel=1 réponse... donc pas d'inscription dans la liste)
Oui mais dans ce cas, le thread dédié doit envoyer dans la pile les messages qui ne le concernent pas (les messages n'arrivent pas forcément dans l'ordre) : ça revient à avoir plein de procédures qui essayent d'écrire dans la pile gérée par le MUTEX : n'est-ce pas un peu risqué ? de mémoire de mes vieux cours d'info, les MUTEX évites les écritures simultanées mais il y avait quand même une probabilité non-nulle de double verrouillage, non ?
En tout cas, plusieurs MUTEX en cours par plusieurs threads risque de décaler le thread principal qui serait lancé par un timer, non ?

Re: Thread (encore une fois) et interruption

Publié : lun. 30/juil./2012 15:26
par Backup
Golfy a écrit : ça revient à avoir plein de procédures qui essayent d'écrire dans la pile gérée par le MUTEX :
c'est pas du tout ce que je dis :)

mais je dois dire que sans avoir le Code + l'interface en question sous les yaux , c'est pas evident de te conseiller ..

je dis que ta pile (j'ai appelé ça liste moi .. ) ne devrai pas centraliser tout les messages !

( ne parlons pas de thread pour le moment)

je dis , qu'il te faudrait une procedure qui envoies les "demandes utilisateur" et qui réceptionnent les messages renvoyé par ta carte au coup par coup ( a la demande )
par exemple changer la tension d'une prise de courant .. (variateur)

je te rappel que je n'y connais rien en velbus ;)

mais j'imagine un dialogue comme ça :

[procedure utilisateur]
demande : je veux baisser la tension de la prise numero 5
attente reponse
reçois la reponse "ok c'est fait"
[/procedure utilisateur]