Thread (encore une fois) et interruption

Programmation d'applications complexes
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Thread (encore une fois) et interruption

Message 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 yeux , c'est pas évident 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 :

DO

[procedure utilisateur] ; cette procedure est appelé a la demande d'une interface utilisateur par exemple (plutot en ecriture )
demande a la carte: je veux baisser la tension de la prise numero 5
attente reponse de la carte
reçois la reponse "ok c'est fait"
[/procedure utilisateur]



[timer toute les 1 minute]

[procedure system] ; cette procedure sera appelé par le timer de temps en temps histoire de rafraichir les controls du systeme (plutot en lecture)
verifie que [procedure utilisateur] n'est pas en cours ( par mutex ou par flag ).. pour ne pas embrouiller la carte avec trop de demandes a la fois
demande a la carte: envoie moi l'etat du system
attente reponse de la carte
reçois la reponse ( valeur des temperatures des pieces, valeur des lumieres , valeur de l'ouverture des portes ..et dieu sait quoi d'autre )

filtre des valeurs renvoyés (dans une pile s'il y en a beaucoup ) et dispache pour par exemple dessin d'une page de diagnostique ou autre....
[/procedure system]


[/timer]

LOOP
voila c'est tres shematisé hein .... ;)
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

Pas de soucis Dobro, bien au contraire ! tes suggestions me permettent d'avancer et si j'essaye de d'écrire le fonctionnement du BUS Velbus c'est parce que tous les bus fonctionnent de manière similaire (oui, oui ! même et surtout ceux embarqués dans les voitures) :)

Revenons au test que je viens de faire :
Voici mon appel au thread :

Code : Tout sélectionner

th= CreateThread(@ReadBUS(),0)
Debug "Thread = " + Str(th) + "          System threadID = "+Str(ThreadID(th))
dans le programme, voici la procédure :

Code : Tout sélectionner

Procedure ReadBUS(void.i)
	z = 1
	Repeat
		d = ElapsedMilliseconds()
		LectureNet()
		Delay(2)
		Debug ElapsedMilliseconds()-d
		Until z = 0
EndProcedure
et la procédure qui utilise les données reçues (notez : j'ai commenté l'appel à LectureNet() puisque le thread est actif dans une boucle infinie)

Code : Tout sélectionner

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()
		AskTempSensor(*BufOut, Val("$"+Amodule.s))
		Repeat
			oldvalue = ListSize(BusCommand())
			Repeat
				; LectureNet()
			Until ListSize(BusCommand()) <> oldvalue
                        debug "OUT : msg coming"
			temp.d = SearchTemp(Amodule.s, time.i-5)
			AskTempSensor(*BufOut, Val("$"+Amodule.s))
		Until temp.d > -274
		ProcedureReturn temp.d
	EndIf
	ProcedureReturn -275
EndProcedure
Résultat : le programme ne répond plus (y compris à Windows qui me propose une fermeture sauvage) et voici les log :
=========================== MODULES : 256
ini file found
Starting network on nautilus
Connexion au server établie : 33673040
Thread = 1 System threadID = 292
-----------------------------------
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
0
0
0
0
0
16
0
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
0
0
0
0
0
16
0
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
0
0
0
0
16
0
0
0
0
0
0
0
15
0
0
READ = 1--> VMB4RY GROUP MOD_1
READ = 2--> VMB4RY GROUP MOD_2
READ = 4--> VMB4RY GROUP MOD_4
READ = 6--> VMB6IN GROUP MOD_6
READ = 7--> VMB4RY GROUP MOD_7
...
READ = 209--> VMB8PB GROUP MOD_209
0
0
16
0
0
0
0
0
0
16
0
0
0
0
0
Temp > 0FFB7102E5009E04 à 1343677223
0
0
15
0
0
0
0
0
0
0
16
0
0 <------ bloqué à partir d'ici !
On voit clairement que la boucle repeat/until de la procédure GetTemp bloque le thread
Normalement, le thread devrait continuer à l'infini ?
[RESOLU] le plantage ici est normal a cause de l'écriture dans une fenêtre (qui n'appartient pas au thread) !
Dernière modification par Golfy le lun. 30/juil./2012 22:56, modifié 1 fois.
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Thread (encore une fois) et interruption

Message par G-Rom »

Pourquoi tu thread ton programme ? En as tu réellement besoin ? je ne pense pas.
Rien ne t'empêche de surveiller le réseau , de recevoir les paquets , de les mettre dans une liste, puis de traité la liste ensuite le tout sans thread et surtout , sans debug , utilise printn() à la place dans une belle console, ou une fenêtre relié à la sortie standard.
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

G-Rom a écrit :Pourquoi tu thread ton programme ? En as tu réellement besoin ? je ne pense pas.
[Mode=joke]Je n'ai pas besoin de voiture, ni d'ordinateur dans ce cas [/joke] :wink:
D'autres parties de mon programme ont besoins de temps (scanner tous les modules, scanner tout les noms des parties des modules, faire les graphiques et écrire les fichiers, etc.)
Jusqu'à maintenant je contournais la difficulté sans thread (mais avec des appels à LectureNet()+windowevent() dans toutes mes procédures) mais ce n'est pas une méthode propre : quand je vais dépasser les 5000 lignes de codes, le moindre problème deviendra ingérable ! :|

Et puis le multitâche est vraiment fait pour ça : un thread qui remplit une liste (provenant de messages asynchrones) et des procédures qui viennent piocher ce dont elles ont besoins.
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

Voici un code de test : il y a vraiment un problème !

Code : Tout sélectionner

Global cnt
Global dte

Procedure tachecompte(void.i)
	z = 0
	cnt = 0
	d = ElapsedMilliseconds()
	Repeat
		cnt+1
		Repeat
		Until ElapsedMilliseconds()-d > 1000
	Until z = 1
EndProcedure

Procedure affichedate()
	SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()-dte))
	g = ElapsedMilliseconds()
	Repeat
	Until ElapsedMilliseconds()-g>200
EndProcedure

OpenWindow(0,100,100,200,400,"TestThread")
TextGadget(1, 10,10,250,20,"date",#PB_Text_Border)
TextGadget(2, 10,30,250,20,"cnt",#PB_Text_Border)

th = CreateThread(@tachecompte(),1000)
If th
	dte=Date()
	Repeat
		affichedate()
		SetGadgetText(2, Str(cnt)+" ")
		a = WindowEvent()
	Until th = 0 Or a = #PB_Event_CloseWindow
EndIf
KillThread(th)
CloseWindow(0)
Dernière modification par Golfy le lun. 30/juil./2012 21:04, modifié 1 fois.
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Thread (encore une fois) et interruption

Message par G-Rom »

mode joke too a écrit :Global cnt

Procedure tachecompte(void.i)
z = 0
cnt = 0
d = ElapsedMilliseconds()
Repeat
cnt+1
Repeat
Until ElapsedMilliseconds()-d > 1000
Until z = 1
EndProcedure

Procedure affichedate()
SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()))
; g = ElapsedMilliseconds()
; Repeat
; Until ElapsedMilliseconds()-g>200
EndProcedure

OpenWindow(0,100,100,200,400,"TestThread")
TextGadget(1, 10,10,250,20,"date",#PB_Text_Border)
TextGadget(2, 10,30,250,20,"cnt",#PB_Text_Border)


timer = ElapsedMilliseconds() + 10

th = CreateThread(@tachecompte(),0)
If th
Repeat

a = WindowEvent()

If timer < ElapsedMilliseconds()
timer = ElapsedMilliseconds() + 75
affichedate()
SetGadgetText(2, Str(cnt))
EndIf



Until th = 0 Or a = #PB_Event_CloseWindow
EndIf
KillThread(th)
CloseWindow(0)
Effectivement , le problème viens de ton code , ou de l'interface chaise / clavier , comme tu veut... :D

Edit:

Evite la mise à jour des gadget en temps réel, le re-dessin bouffe du temps processeur.
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

G-Rom a écrit : Effectivement , le problème viens de ton code , ou de l'interface chaise / clavier , comme tu veut... :D

Edit:

Evite la mise à jour des gadget en temps réel, le re-dessin bouffe du temps processeur.
Oui effectivement... depuis que je fait de l'informatique j'ai remarqué un gros bug à cette place *lol*
pourquoi la variable cnt n'évolue pas de seconde en seconde (du fait de la boucle > 1000) ???
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Thread (encore une fois) et interruption

Message par G-Rom »

Parceque tu est bloqué dans le repeat/until pendant x ms
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

Un code qui marche mieux... mais utilise la fonction dont il ne faut pas prononcer le nom (delay) : la fonction threadé ne s'exécute que toute les secondes tandis que la fonction principale tourne à fond... là, je vois un vrai multithread :)

Code : Tout sélectionner

Global cnt
Global dte
Global ddd

Procedure tachecompte(void.i)
	z = 0
	cnt = 0
	d = ElapsedMilliseconds()
	Repeat
		;Repeat
		;Until ElapsedMilliseconds()-d > 1000
		Delay(1000)
		cnt+1
	Until z = 1
EndProcedure
;-----
Procedure affichedate()
	SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()-dte)+" - "+Str((ElapsedMilliseconds()-ddd)/100))
EndProcedure
;-----
OpenWindow(0,100,100,200,100,"TestThread")
TextGadget(1, 10,10,170,20,"date",#PB_Text_Border)
TextGadget(2, 10,30,170,20,"cnt",#PB_Text_Border)
;=====
th = CreateThread(@tachecompte(),1000)
If th
	dte=Date()
	ddd = ElapsedMilliseconds()
	Repeat
		;ddd = ElapsedMilliseconds()
		affichedate()
		SetGadgetText(2, Str(cnt)+" ")
		a = WaitWindowEvent(500)
	Until th = 0 Or a = #PB_Event_CloseWindow
EndIf
KillThread(th)
CloseWindow(0)	
Dernière modification par Golfy le lun. 30/juil./2012 21:37, modifié 1 fois.
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Thread (encore une fois) et interruption

Message par G-Rom »

Tu ne met pas a jour d aussi. C'est donc de plus en plus long.... ;)
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

Voici un code qui permettra de comparer les avantages et inconvénients de chaque fonction (timer, thread, main)

Code : Tout sélectionner

Global cnt
Global dte
Global ddd
Global gct.d

Procedure tachecompte(void.i)
	z = 0
	cnt = 0
	Repeat
		Delay(1000)
		cnt+1
	Until z = 1
EndProcedure

Procedure affichedate()
	SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()-dte)+" - "+Str((ElapsedMilliseconds()-ddd)/100))
EndProcedure

Procedure globalcount()
	gct = gct + 0.1
EndProcedure
	
OpenWindow(0,100,100,200,100,"TestThread")
TextGadget(1, 70,10,120,20,"date",#PB_Text_Border)
TextGadget(2, 70,30,120,20,"cnt",#PB_Text_Border)
TextGadget(3, 70,50,120,20,"timercnt",#PB_Text_Border)
TextGadget(7, 10,10,120,20,"main")
TextGadget(8, 10,30,120,20,"thread")
TextGadget(9, 10,50,120,20,"timer")
AddWindowTimer(0, 2012, 100)

th = CreateThread(@tachecompte(),1000)
If th
	dte=Date()
	ddd = ElapsedMilliseconds()
	Repeat
		affichedate()
		SetGadgetText(2, Str(cnt)+" ")
		SetGadgetText(3, StrD(gct,1)+" ")
		a = WaitWindowEvent(500)
		If a = #PB_Event_Timer And EventTimer() = 2012
			globalcount()
		EndIf
	Until th = 0 Or a = #PB_Event_CloseWindow
EndIf
KillThread(th)
CloseWindow(0)
A NOTER : déplacer la fenêtre pendant 5 secondes donnera 5 secondes de retard au compteur basé sur un timer --> je ne peux pas utiliser un timer pour gérer la réception de mes messages BUS (cela explique également l'avertissement dans la doc sur la fonction timer)
Pour le reste, c'est assez cohérent.
Dobro ou toi : pensez-vous que ce programme puisse servir de base pour un tutorial ? il me semble suffisamment court et contenir assez de fonctions... (sous réserve d'ajouter les commentaires idoines bien sur)
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Thread (encore une fois) et interruption

Message par Backup »

Golfy a écrit : A NOTER : déplacer la fenêtre pendant 5 secondes donnera 5 secondes de retard au compteur basé sur un timer --> je ne peux pas utiliser un timer pour gérer la réception de mes messages BUS (cela explique également l'avertissement dans la doc sur la fonction timer)
sauf que tu n'utilise pas comme il faut les timer !! :roll:
Dobro ou toi : pensez-vous que ce programme puisse servir de base pour un tutorial ? il me semble suffisamment court et contenir assez de fonctions... (sous réserve d'ajouter les commentaires idoines bien sur)
pas vraiment non , car comme je te le dis depuis le debut , ton code n'est pas correcte !

allez encore une piste :
pour le "main" il faut utiliser un callback si tu ne veux pas de blocage
pour le timer, utilise la forme que je t'ai indiqué (meme sans callback ça marche niquel ! )

ps : on n'utilise pas KillThread () !!
un thread se vire de la ram lorsqu'il a fini ! (c'est Fred lui meme qui le dit )
Dernière modification par Backup le mar. 31/juil./2012 0:23, modifié 3 fois.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Thread (encore une fois) et interruption

Message par G-Rom »

Ton code 2 posts plus haut est bancal , en plus tu ne tiens pas compte de mes remarques :
Global cnt
Global dte
Global ddd
Global updateTimer.i
Procedure tachecompte(void.i)
z = 0
cnt = 0
d = ElapsedMilliseconds()
Repeat
Repeat
Until ElapsedMilliseconds()-d > 1000
cnt+1
d = ElapsedMilliseconds() ; MISE A JOUR DE D

ForEver ; Until z = 1 ????
EndProcedure
;-----
Procedure affichedate()
SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()-dte)+" - "+Str((ElapsedMilliseconds()-ddd)/100))
EndProcedure
;-----
OpenWindow(0,100,100,200,100,"TestThread")
TextGadget(1, 10,10,170,20,"date",#PB_Text_Border)
TextGadget(2, 10,30,170,20,"cnt",#PB_Text_Border)
;=====


th = CreateThread(@tachecompte(),1000)
If th
dte=Date()
ddd = ElapsedMilliseconds()
Repeat
a = WindowEvent()
If updateTimer < ElapsedMilliseconds()
updateTimer = ElapsedMilliseconds() + 75

affichedate()
SetGadgetText(2, Str(cnt)+" ")
EndIf
Until th = 0 Or a = #PB_Event_CloseWindow
EndIf
KillThread(th)
CloseWindow(0)
Là ça marche bien , ça clignote pas.

pour en revenir au sujet principal , Je ne vois pas en quoi les threads vont aider dans ton projet , ni même le rapport avec la taille de celui ci.

thread ou pas thread , tout sera fait de manière séquentiel que tu le veuilles ou non , on a pas encore d'ordinateur quantique.
seul le partage du temps sera différent.

je résume ce que j'ai compris :
IF RECOIS MESSAGE = VRAI
LECTURE MESSAGE
METTRE DANS LISTE
SINON
TRAITER LES MESSAGES
je traite des informations à 19600 bauds sans aucun thread dans mes projet electro/info. Avant de faire une appli impossible à debogué avec 50 milles thread qui tournent dans le vide , fait une appli qui marche sans thread , et vois après ce que tu peut encore optimisé. c'était mon conseil du soir :)
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Thread (encore une fois) et interruption

Message par Backup »

+1 avec G-Rom ;)

tiens voici ton exemple avec tout
mais ça reste un code pas terrible
car il n'y a pas de constante , ( je suis parti de ton code ... )

j'aime pas les codes avec des gadgets numéroté , alors qu'on pourrai avoir des constantes plus parlante ...

mais bon c'est juste pour te démontrer qu'un code mal architecturé ne fonctionne pas
mais en le modifiant, on peut arriver a tout faire cohabiter ;) (meme le timer )

Code : Tout sélectionner

Global cnt
Global dte
Global ddd
Global gct.d
#timer_1=1

Declare  tachecompte(void.i)
Declare  affichedate()
Declare  globalcount()
Declare  TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
Declare  WindowCallback(WindowID,message,wParam,lParam)



OpenWindow(0,100,100,200,100,"TestThread")
TextGadget(1, 70,10,120,20,"date",#PB_Text_Border)
TextGadget(2, 70,30,120,20,"cnt",#PB_Text_Border)
TextGadget(3, 70,50,120,20,"timercnt",#PB_Text_Border)
TextGadget(7, 10,10,120,20,"main")
TextGadget(8, 10,30,120,20,"thread")
TextGadget(9, 10,50,120,20,"timer")

; **** preparation du bin's ***********
SetTimer_(WindowId(0), #timer_1, 1000, @TimerProc()) ; active le timer
SetWindowCallback(@WindowCallback()) ; active le callback

th = CreateThread(@tachecompte(),1000) ; active le Thread
dte=Date()
ddd = ElapsedMilliseconds()
; ****** fin de preparation du bin's ******


; *** boucle principale ******
Repeat
	affichedate()
	
	select waitWindowEvent(2)
		
		case #PB_Event_CloseWindow
		break
	endselect
forever
; **** fin boucle principale ***
CloseWindow(0)
End



; ************* zone des procedures *******************
Procedure tachecompte(void.i) 
	; le Thread
	z = 0
	cnt = 0
	Repeat
		Delay(1000)
		cnt+1
		SetGadgetText(2, Str(cnt)+" ")
	forever
EndProcedure

Procedure affichedate()
	; le main joué par le callback
	SetGadgetText(1,FormatDate("%hh:%ii:%ss", Date()-dte)+" - "+Str((ElapsedMilliseconds()-ddd)/100))
EndProcedure

Procedure globalcount()
	; le code joué par le timer
	gct = gct + 0.1
	SetGadgetText(3, StrD(gct,1)+" ")     
	
EndProcedure


Procedure TimerProc(hwnd.l, uMsg.l, idEvent.l, dwTime.l)
	Select uMsg
		Case #WM_TIMER
		Select idEvent
			Case  #timer_1
			globalcount()
		EndSelect
	EndSelect
EndProcedure


Procedure WindowCallback(WindowID,message,wParam,lParam)
	; by Dobro
	res=#PB_ProcessPureBasicEvents
	Select message
		case #WM_MOVE ; se charge de continuer a incrementer la date si on bouge la fenetre !! 
		affichedate()
		ProcedureReturn #True
	EndSelect
	ProcedureReturn res ; important , laissez passer les autres evenements !!!
EndProcedure
; EPB

remue ta fenêtre , tout fonctionne ! :) surtout le Timer !! :lol:

ps: tout ça devrai etre bougé en section debutant ....
Golfy
Messages : 423
Inscription : mer. 25/août/2004 15:14
Localisation : Grenoble
Contact :

Re: Thread (encore une fois) et interruption

Message par Golfy »

Merci pour vos indications.
1) Je note que le programme de Dobro fonctionne avec des appels à des API Windows... quid si je compile sous Linux (oui certains utilisateurs Velbus sont Win, d'autres Linux) ? les timer Purebasic ne sont pas fiables ?
2) Je cherchais (mal je suppose) l'équivalent DO...LOOP du GFABasic : en Purebasic c'est REPEAT...FOREVER, merci !
3) Je veux remplir ma liste en arrière plan quoiqu'il arrive, sans perte de message, overflow ou latence : tu imagines si mon programme rate l'appui du bouton 'ALARME' juste parce qu'il est en train de traiter autre chose ?
4) OK pour déplacement en débutant
Purebasic 5.30 full sous Windows XP (x86) et Win7 (64 bits), Linux Debian. Orientation réseaux, domotique
http://golfy.olympe.in/Teo-Tea/
Répondre