Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls)

Sujets variés concernant le développement en PureBasic
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls)

Message par falsam »

Je vous propose de tester ce code qui va se charger de lire une photo de 100 bits, bits par bits.

Pour accélérer le traitement, quatre thread vont se partager le travail.

Le premier lira les 25 premiers bits, le suivant les 25 suivants, etc ....

■ Premier code sans mutex.

Code : Tout sélectionner

Declare Start()
Declare Process(*Numero)

;Photo
Global n = 100, Dim Photo(n), Segment = 25 

;Thread
Global Thread0, Thread1, Thread2, Thread3

Start()
Procedure Start()
  Protected i
  
  ;Création de la photo
  For i = 0 To n
    Photo(i) = i  
  Next
  
  thread0 = CreateThread(@Process(), 0)
  thread1 = CreateThread(@Process(), 1)
  thread2 = CreateThread(@Process(), 2)
  thread3 = CreateThread(@Process(), 3)
  MessageRequester("Information", "Touche entrée pour terminer")
EndProcedure

Procedure Process(*Numero)       
  Debug #CRLF$ + "Le Thread " + Str(*Numero) + " lit les bits de " + Str(*Numero * Segment) + " à " + Str(((*numero * Segment) + Segment)-1)
  
  For b = (*Numero * Segment) To ((*numero * Segment ) + Segment) - 1 
    Debug "Thread " + Str(*Numero) + " lecture cellule " + Str(Photo(b)) 
  Next   
EndProcedure
- Si vous le compiler sans option thread, vous allez voir un horrible résultat.
- Si vous le compiler avec l'option Thread dans les options de compilation. Vous verrez que les threads fonctionnent mais avec un résultat dans le désordre.
Debug a écrit :...
Le Thread 3 lit les bits de 75 à 99
[12 :21 :59] Thread 0 lecture cellule 20
[12 :21 :59] Thread 1 lecture cellule 32
[12 :21 :59] Thread 0 lecture cellule 21
[12 :21 :59] Thread 3 lecture cellule 75
[12 :21 :59] Thread 2 lecture cellule 51
[12 :21 :59] Thread 3 lecture cellule 76
[12 :21 :59] Thread 1 lecture cellule 33
[12 :21 :59] Thread 0 lecture cellule 22
[12 :21 :59] Thread 1 lecture cellule 34
[12 :21 :59] Thread 2 lecture cellule 52
[12 :21 :59] Thread 1 lecture cellule 35
...
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^

Message par falsam »

Essayons d'arranger le code en ajoutant un WaitThread()

Code : Tout sélectionner

Declare Start()
Declare Process(*Numero)

;Photo
Global n = 100, Dim Photo(n), Segment = 25 

;Thread
Global Thread0, Thread1, Thread2, Thread3

Start()
Procedure Start()
  Protected i
  
  ;Création de la photo
  For i = 0 To n
    Photo(i) = i  
  Next
  
  Mutex = CreateMutex()
  
  thread0 = CreateThread(@Process(), 0)
  thread1 = CreateThread(@Process(), 1)
  thread2 = CreateThread(@Process(), 2)
  thread3 = CreateThread(@Process(), 3)
  
  WaitThread(thread0)
  WaitThread(thread1)
  WaitThread(thread2)
  WaitThread(thread3)
  
  MessageRequester("Information", "Touche entrée pour terminer")
EndProcedure

Procedure Process(*Numero)       
  Debug #CRLF$ + "Le Thread " + Str(*Numero) + " lit les bits de " + Str(*Numero * Segment) + " à " + Str(((*numero * Segment) + Segment)-1)
  
  For b = (*Numero * Segment) To ((*numero * Segment ) + Segment) - 1 
    Debug "Thread " + Str(*Numero) + " lecture cellule " + Str(Photo(b)) 
  Next   
EndProcedure
Les threads se lancent bien dans l'ordre, mais le résultat n'est pas correcte.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^

Message par falsam »

C'est là que va intervenir la brigade des Mutex() avec ce nouveau code.

Code : Tout sélectionner

Declare Start()
Declare Process(*Numero)

;Photo
Global n = 100, Dim Photo(n), Segment = 25 

;Thread
Global Mutex, Thread0, Thread1, Thread2, Thread3

Start()
Procedure Start()
  Protected i
  
  ;Création de la photo
  For i = 0 To n
    Photo(i) = i  
  Next
  
  Mutex = CreateMutex()
  
  thread0 = CreateThread(@Process(), 0)
  thread1 = CreateThread(@Process(), 1)
  thread2 = CreateThread(@Process(), 2)
  thread3 = CreateThread(@Process(), 3)
  
  WaitThread(thread0)
  WaitThread(thread1)
  WaitThread(thread2)
  WaitThread(thread3)
  
  MessageRequester("Information", "Touche entrée pour terminer")
EndProcedure

Procedure Process(*Numero)     
  Shared Mutex
  
  LockMutex(Mutex)    
  
  Debug #CRLF$ + "Le Thread " + Str(*Numero) + " lit les bits de " + Str(*Numero * Segment) + " à " + Str(((*numero * Segment) + Segment)-1)
  
  For b = (*Numero * Segment) To ((*numero * Segment ) + Segment) - 1 
    Debug "Thread " + Str(*Numero) + " lecture cellule " + Str(Photo(b)) 
  Next 
  
  UnlockMutex(Mutex)  
EndProcedure
Cette fois çi le résultat est correcte.
Debug a écrit : Le Thread 0 lit les bits de 0 à 24
[12 :28 :30] Thread 0 lecture cellule 0
[12 :28 :30] Thread 0 lecture cellule 1
[12 :28 :30] Thread 0 lecture cellule 2
[12 :28 :30] Thread 0 lecture cellule 3
[12 :28 :30] Thread 0 lecture cellule 4
[12 :28 :30] Thread 0 lecture cellule 5
[12 :28 :30] Thread 0 lecture cellule 6
[12 :28 :30] Thread 0 lecture cellule 7
[12 :28 :30] Thread 0 lecture cellule 8
[12 :28 :30] Thread 0 lecture cellule 9
[12 :28 :30] Thread 0 lecture cellule 10
[12 :28 :30] Thread 0 lecture cellule 11
[12 :28 :30] Thread 0 lecture cellule 12
[12 :28 :30] Thread 0 lecture cellule 13
[12 :28 :30] Thread 0 lecture cellule 14
[12 :28 :30] Thread 0 lecture cellule 15
[12 :28 :30] Thread 0 lecture cellule 16
[12 :28 :30] Thread 0 lecture cellule 17
[12 :28 :30] Thread 0 lecture cellule 18
[12 :28 :30] Thread 0 lecture cellule 19
[12 :28 :30] Thread 0 lecture cellule 20
[12 :28 :30] Thread 0 lecture cellule 21
[12 :28 :30] Thread 0 lecture cellule 22
[12 :28 :30] Thread 0 lecture cellule 23
[12 :28 :30] Thread 0 lecture cellule 24
...
C'est tout pour aujourd'hui .... enfin presque :p
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Zorro »

exemple d'application des Threads sans Mutex (et sans bazar !! )

CQFD ! ;)
ici l'image chargé se dessine en trois partie chaque Thread a sa partie a dessiner ....
peut importe l'orde, de toute façons, l'image sera dessinée entierement dans tout les cas

juste pour dire qu'on peut utiliser les Threads sans Mutex

par contre le flag ThreadSafe, est juste là pour garantir une intégrité des Chaines ... ne pas confondre

un algo qui utilise les Threads a pour but de "paralélliser" des sous parties )

soit les Mutex sont recommandé pour synchroniser les sous Parties d'un Algo
soit on ne les utilisent pas , parcequ'il n'apporte rien de mieux dans l'algo
par exemple un algo de travail sur image comme ici
le sens du travail de chaque partie, n'a pas d'importance, seul le résultat compte
il y a des tas d'application ou l'ordre , ben on s'en fout :)

ps: juste une truc quand meme , je pensais qu'en utilisant des Threads pour les 3 partie de l'image
ça irai plus vite ... ben c'ets pas le cas :lol:

Code : Tout sélectionner




Global bitmap
Global Form1,largeur,hauteur
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTIFFImageDecoder()
UseTGAImageDecoder() 
Declare thread1(bidon)
Declare thread2(bidon)
Declare thread3(bidon)
Declare open_window_0()

Declare open_window_0()

Enumeration
		#Win
		#Image 
EndEnumeration


NomFichier$ = OpenFileRequester("Choisir une image", "c:\", "Images|*.*", 0)
bitmap = LoadImage(#Image , NomFichier$) 
ResizeImage(#image,800,600)
Global largeur = ImageWidth(#Image)
Global hauteur = ImageHeight(#Image) 

; ***** mise en tableau de l'image ******

Global Dim Tab(Largeur,Hauteur)
StartDrawing(imageOutput(#Image))	
For y=1 to Hauteur-1
		For x=1 to Largeur-1
				Tab(x,y)=point(x,y)
		Next x
Next y
StopDrawing()
; **********************************

Open_Window_0()


	; Dessin de l'image dans la fenetre par procedure simple
;Thread1(bidon)
;Thread2(bidon)
;Thread3(bidon)
; *******************************************************

; Dessin de l'image dans la fenetre par THreads SANS MUTEX (Marche mais beaucoup beaucoup plus lent.... mais Marche)
DisableDebugger
StartDrawing(WindowOutput(#win))		
CreateThread(@Thread1(),*bidon)
CreateThread(@Thread2(),*bidon)
CreateThread(@Thread3(),*bidon)
EnableDebugger


Repeat 
		Event = WaitWindowEvent(2) 
	



Until Event = #PB_Event_CloseWindow
End 


Procedure Thread1(bidon)
; premier tier
		StartDrawing(WindowOutput(#win))
		Dep =1
		max=Hauteur/3
				For y=dep to  max-1
						For x=1 to largeur-1
								Plot (x,y,Tab(x,y))
						Next x
				Next y
		StopDrawing()
EndProcedure

Procedure Thread2(bidon)
; deuxieme tier
		StartDrawing(WindowOutput(#win))
			Dep=Hauteur/3
				max=(Hauteur/3)*2
			
				For y= Dep to  max-1
						For x=1 to Largeur-1
								Plot (x,y,Tab(x,y))
						Next x
				Next y
		StopDrawing()
EndProcedure

Procedure Thread3(bidon)
; dernier tier
		StartDrawing(WindowOutput(#win))
		dep=(Hauteur/3)*2
				max=Hauteur
				For y=Dep to max-1
						For x=1 to Largeur-1; 

								Plot (x,y,Tab(x,y))
						Next x
				Next y
		StopDrawing()
EndProcedure



Procedure Open_Window_0()
		Form1=OpenWindow(#Win ,0,0,largeur,hauteur,"",#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) 
		
EndProcedure



; 
; EPB 

Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par falsam »

exemple d'application des Threads sans Mutex (et sans bazar !! )
Si tu veux prouver que ce bazar ne sert à rien et bien tu te trompes car tu as crée autant de procédures qu'il y a de threads.

Dans l'exemple que je cite, il n'y a qu'une seule procédure qui est lancé quatre fois.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Zorro »

alors pardon, mais en principe un thread est attribué a une tache précise !

utiliser une seule procedure pour la Threader plusieurs fois n'a pas de sens .. (meme si ça peut se concevoir )

mais c'est comme vouloir faire de la Stereo avec une seule source sonore :)

le but des thread n'est pas d'avoir une procedures qui va servir en "paralelle"

mais bien d'avoir plusieurs procedures qui bossent de concert !

d'ailleurs Chaque Thread a sa propre Pile D'appel ....son propre context ...


pour "diviser" ou réutiliser une seule procedure comme tu le fait, c'est plutot du coté de la récursivité , qu'il faut regarder ...

Mais je le repete, les Threads sont des sous-routines (en principe de nature differente) qui travaillent de concert ... :)

ps: "sans bazar" voulait faire allusion au fait que des parties ne s'executent pas dans l'ordre , comme tu l'a souligné dans ton exemple
d'ailleurs je le dit ici :
le sens du travail de chaque partie, n'a pas d'importance, seul le résultat compte
il y a des tas d'applications des threads ou l'ordre , ben on s'en fout :)
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par falsam »

utiliser une seule procedure pour la Threader plusieurs fois n'a pas de sens ..
Quelle ineptie !!!!
Heureusement que tu portes un masque. Ça te permet de rester incognito.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par G-Rom »

utiliser une seule procedure pour la Threader plusieurs fois n'a pas de sens
Tu est une blague ambulante , son code avec les images montrent très bien l'utilité
d'ailleurs Chaque Thread a sa propre Pile D'appel ....son propre context ...
utilise pas des mots compliqué , les thread partages les même ressource, d'ou les mutex...
il y a des tas d'application ou l'ordre , ben on s'en fout
C'est pas une question d'ordre, mais une question d'accès concurrentiel , il est important de pouvoir correctement synchroniser les threads.

https://fr.wikipedia.org/wiki/Exclusion_mutuelle

Evidement, tu n'as pas besoin de thread en cas de non accès concurrentiel, un thread sans mutex peut être appelé pour l'appel d'une fonction bloquante , ce qui laisse le main thread non bloqué.
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Zorro »

G-Rom a écrit :
d'ailleurs Chaque Thread a sa propre Pile D'appel ....son propre context ...
utilise pas des mots compliqué , les thread partages les même ressource, d'ou les mutex...
non , je dis non ! (ref: Brice de Nice)
il y a tromperie intellectuel (tin vla que je me met a parler comme Olivier :lol:) )
en realité les Mutex ne sont utiles QUE et seulement QUE si le meme espace est partagé par plusieurs Threads ET que cet espace a une importance pour l'un des Threads !

sinon, et mon exemple le démontre tres bien on peut Threader sans avoir besoin de Mutex .

si t'a deja tracé du Prg , tu saurai q'un Thread a sa propre Pile...
ce qui compte c'est l'espace dans lequel il lit ou il ecrit ... là , lui peut etre partagé , et dans ce Cas le Mutex est obligatoire...(enfin conseillé )
il y a des tas d'applications ou l'ordre , ben on s'en fout
C'est pas une question d'ordre, mais une question d'accès concurrentiel , il est important de pouvoir correctement synchroniser les threads.

Evidement, tu n'as pas besoin de thread en cas de non accès concurrentiel, un thread sans mutex peut être appelé pour l'appel d'une fonction bloquante , ce qui laisse le main thread non bloqué.

ben voila, on est enfin d'accord ! c'est ce que je dis

vous avez présenté ce matin les Mutex comme une obligation ... je me pose en faux la dessus , rien de plus :)
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par G-Rom »

Zorro a écrit : vous avez présenté ce matin les Mutex comme une obligation ... je me pose en faux la dessus , rien de plus :)
Obligation n'est pas le bon terme, mais plutôt "vivement recommandé" dès lors que tu utilises des fonctions tierce susceptible d'utilisé un espace partagé.
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Ollivier »

@Falsam

Moi, je vais te dire que je suis pour.

Maintenant, peux-tu me faire une procédure lambda qui soit "serveur" si elle ne détecte pas d'autre threads, et "client" si elle détecte un autre thread, et qu'elle a pu communiquer avec pour vérifier qu'elle avait bien affaire à un thread "serveur" et effectuer sa tâche principale?

Nota :
1) Le thread "serveur" a pour tâche principale de publier des nombres aléatoires toutes les secondes.

2) Le thread "client" a pour tâche principale d'afficher les nombres publiés sans problème de freezing.

3) Il n'est pas interdit de rajouter x procédures sous-jacentes à la procédure Lambda pour que la procédure Lambda soit plus lisible (et qu'on comprenne alors les atouts des mutex).
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par falsam »

Ollivier a écrit :Maintenant, peux-tu me faire une procédure lambda qui soit "serveur" si elle ne détecte pas d'autre threads, et "client" si elle détecte un autre thread, et qu'elle a pu communiquer avec pour vérifier qu'elle avait bien affaire à un thread "serveur" et effectuer sa tâche principale?
NON

L'objectif était de montrer l’intérêt des mutex avec un exemple très simple.

Si tu le souhaites, tu peux faire l'exercice que tu me préconise de faire.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Ollivier »

Ce n'est pas une question-piège.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par falsam »

Ollivier a écrit :Ce n'est pas une question-piège.
Tout à fait d'accord. A toi l'honneur du code.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Pour ou contre les Mutex ^-^ (Ou les mutex pour les Nuls

Message par Ollivier »

M'en voudras-tu si, pour des raisons qui ne me concernent pas, mon code source ne fonctionne plus dans 8 ans?
Répondre