Seite 5 von 5

Verfasst: 25.01.2007 22:38
von Toshy
Ich habe auch nochmal einen Code gebastelt, hatte nur etwas gedauert.

Code: Alles auswählen

Global b.l
Global wait.b
Procedure thread1(d)
   While wait = 0
  Wend
   For i = 1 To 10
    b = 1
    test.s = Space(1000000)
    Debug "thread1: " + Str(b)
  Next
EndProcedure
Procedure thread2(d)
   wait = 1
  Delay(0)
  For i = 1 To 10
    b = 2
   test.s = Space(1000000)
    Debug "thread2: " + Str(b)
  Next
EndProcedure

CreateThread(@thread1(),0)
Delay(1500)
CreateThread(@thread2(),0)

Delay(10000)
Dieser nutzt kein Mutex, die Variable b ist aber "threadsicher", also geschützt. es gibt keine Probleme beim beschreiben oder so.
Allerdings ist der Programmaufbau nicht "threadsicher" wenn du dir die Ausgabe ansiehst, wird dir auffallen, das nicht immer "thread1: 1" oder "thread2: 2" ausgegeben wird wie es laut code sollte, sondern die Werte nach Lust und Laune wechseln.

Willst du den Code thread sicher machen, dann mußt es es in der Art machen wie es remi_meier gepostet hat. in Punkt auf meine Code so:

Code: Alles auswählen

Debug "start"
Global Mutex1 = CreateMutex()
Global Mutex2 = CreateMutex() 
Global b.l
Global wait.b
Procedure thread1(d)
  While wait = 0
  Wend
  For i = 1 To 10
    LockMutex(Mutex1)
    b = 1
    test.s = Space(1000000)
    Debug "thread1: " + Str(b)
    UnlockMutex(Mutex1)
  Next
EndProcedure
Procedure thread2(d)
  wait = 1
  Delay(0)
  For i = 1 To 10
    LockMutex(Mutex1)
    b = 2
    test.s = Space(1000000)
    Debug "thread2: " + Str(b)
    UnlockMutex(Mutex1)
  Next
EndProcedure
LockMutex(Mutex2) ; dieser Zweite Mutex arbeitet unabhängig vom ersten, wenn nicht, dann würde in den Threads nun nichts ausgeführt werden
;LockMutex(Mutex1) ; dies ist der selbe Mutex wie in den Threads, die dadurch nicht weiter arbeiten

CreateThread(@thread1(),0)
Delay(1500)
CreateThread(@thread2(),0)

Delay(10000)

Verfasst: 25.01.2007 22:46
von Toshy
Alle Variablen, die zwischen LockMutex und UnlockMutex verwendet werden,
sind geschützt, nicht genutzte Variablen kann ich z.B. mit einem anderem
Mutex schützen.
Nein, so gesagt stimmt das nicht so ganz. Die Aussage müßte eher sein, die Codeausführung zwischen dem LockMutex und UnlockMutex ist geschützt. Aber wenn du noch andere Threads hast oder sogar der Hauptprozess und diese nicht den selben Mutex und lock verwenden bei der Variable, dann ist dies nicht geschützt.

Code: Alles auswählen

Global a.l, b.l, c.l
Global Mutex1 = CreateMutex()
Global Mutex2 = CreateMutex()


Procedure Thread(d.l)
 
  Repeat
    LockMutex(Mutex1)
    ; Mutex1 schützt einfach mal b
    b = Sin(b)
    UnlockMutex(Mutex1)
   
    LockMutex(Mutex2)
    ; Mutex2 schützt einfach mal a und c
    c = Tan(c)
    a = Cos(a)
    UnlockMutex(Mutex2)
   
    Delay(0)
  ForEver
 
EndProcedure


a = 4
b = 6
c = 7

For z = 0 To 100
  CreateThread(@Thread(), 0)
Next


Repeat
  ;Delay(10)
b = 434
Until GetAsyncKeyState_(#VK_ESCAPE)
Dies kann auch auf die Variable b zugreifen, wären der Thread sie bearbeitet. Zwar kommt das SPeichern nicht durcheinander, da das schreiben in die Variable wie wohl geklärt wurde sicher ist, aber würde im Thread nach dem a= sin() noch eine Debugausgabe oder so kommen, würde da oft 434 drinn stehen.

Verfasst: 26.01.2007 14:27
von remi_meier
@ts-soft:
Toshy hat's schön gesagt :D
Hier noch ein Beispiel, wie man nen Mutex falsch nutzen kann und somit
wieder keine Threadsicherheit hat und deshalb auch keine Variablen
geschützt sind.

Code: Alles auswählen

Global a.l, b.l, c.l 
Global Mutex1 = CreateMutex() 
Global Mutex2 = CreateMutex() 


Procedure Thread(d.l) 
  
  Repeat 
    LockMutex(Mutex1) 
    ; Mutex1 schützt einfach mal b 
    b = Sin(b) 
    UnlockMutex(Mutex1) 
    
    LockMutex(Mutex2) 
    ; Mutex2 schützt einfach mal a und c 
    c = Tan(c) 
    a = Cos(a) 
    UnlockMutex(Mutex2) 
    
    Delay(0) 
  ForEver 
  
EndProcedure 

Procedure Thread2(d.l) 
  
  Repeat 
    ; LockMutex(Mutex1) 
    ; Mutex1 schützt einfach mal b 
    b = Sin(b) 
    ; UnlockMutex(Mutex1) 
    
    ; LockMutex(Mutex2) 
    ; Mutex2 schützt einfach mal a und c 
    c = Tan(c) 
    a = Cos(a) 
    ; UnlockMutex(Mutex2) 
    
    Delay(0) 
  ForEver 
  
EndProcedure 


a = 4 
b = 6 
c = 7 

For z = 0 To 50 
  CreateThread(@Thread(), 0) 
  CreateThread(@Thread2(), 0) 
Next 


Repeat 
  Delay(10) 
Until GetAsyncKeyState_(#VK_ESCAPE)
Thread2() achtet nicht auf die CriticalSections von Thread(), somit ist
alles futsch. Du musst einfach sicherstellen, dass ein Objekt/Variable
immer in der gleichen CS (immer mit dem gleichen Mutex) bearbeitet
wird.

Verfasst: 26.01.2007 19:47
von ts-soft
Das locken des Mutexes muß aber doch nicht in die Repeat Schleife :mrgreen:
Soviel locken kann ja nicht gut sein :wink:

Ich habs begriffen, ich werde es zwar sobald nicht brauchen, aber wer weiß ...

Gruß
Thomas

Verfasst: 26.01.2007 22:14
von remi_meier
Doch natürlich muss das locken des Mutexes in diesem Beispiel in die
Repeat-Schleife rein, da sonst nur ein Thread jemals irgendeine Variable
verändern darf, denn ist der Thread einmal in der CriticalSection, kommt
er in diesem Beispiel nie mehr raus (Repeat-Forever) und somit kann
kein anderer Thread in die gleiche CS gehen und irgendwelche Variablen
'anfassen'. Wäre n Deadlock (Threads für immer blockiert).
Oder habe ich dich falsch verstanden?

Verfasst: 26.01.2007 22:27
von ts-soft
Ich würde den Code so umstellen, das nicht dauernd gelocked wird, wenn
möglich. Da ich mit Anwendungen die sehr viele Threads verwenden sowieso
schlechte Erfahrungen habe (ich meine nicht PB sondern Allgemein) werde
ich es sowieso hoffentlich nicht brauchen :mrgreen:

Asynchrones stört die Harmonie :lol:

Verfasst: 26.01.2007 22:30
von remi_meier
Jo, wenig locken ist sicher gut. Ich habe bis jetzt auch noch nicht viele
Threads benötigt in meinen Projekten, aber wenns halt darum geht,
dass eine Berechnung im Hintergrund abläuft, während die GUI zumindest
neu gezeichnet wird, dann sehe ich das als eine der einfachsten Lösungen
an. (Beispiel: Mein Lindenmayer-System-Programm)