[definitiv Bug] TryLockMutex(Mutex) und LockMutex(Mutex)

Fragen und Bugreports zur PureBasic 4.0-Beta.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

[definitiv Bug] TryLockMutex(Mutex) und LockMutex(Mutex)

Beitrag von Toshy »

[edit]Bugmeldung für Freak im achten Beitrag (06 Feb 2006 21:56:41)
[/edit]

Hi,
wie soll den TryLockMutex(Mutex) genau funktionieren, habe das wohl nicht ganz verstanden und wie soll sich darauf dann LockMutex(Mutex) verhalten.
TryLockMutex(Mutex) soll doch wenn vorhanden den mutex "verriegeln".
Das tut es zwar wohl auch, aber es liefert IMMER nur NULL zurück, das sollte denke ich nicht sein, oder? "otherwise" steht da doch.
Die Funktion TryLockMutex(Mutex) an sich ist sehr sinnvoll, vor allem in kombination mit LockMutex(Mutex), aber damit funktioniert es nicht so richtig bzw. sinnvoll. zwar verriegelt TryLockMutex(Mutex) den codeteil dann für "LockMutex(Mutex)", aber umgekehrt (leider) nicht. das TryLockMutex(Mutex) verriegelt kann ja nur sinnvoll sein, wenn "lockmutex" nicht gleichzeitig mit einem TryLockMutex(Mutex) laufen darf. aber das passiert ja doch, denn wenn lockmutex verriegelt gilt dies leider nicht für TryLockMutex(Mutex).
TryLockMutex(Mutex) liefert bei mir auch immer nur NULL zurück und daher weiß ich leider nicht wie ich beides "vernüpftig" nutzen kann.

kann mir da mal jemand ein bissl was erklären.
ich brauche dies nämlich für einige Critical Sektions, aber für 3 Arten.

1. Nur ein Thread darf den Codeteil nutzen, alle anderen warten.
2. Nur ein Thread darf den Code nutzen, alle anderen warten aber nicht sondern gehen mit einem Rückgabewert weiter so daß ich den codeteil überspringen kann.
3. Alle Threads dürfen den Codeteil gleichzeitig nutzen, außer wenn einer dies nicht zuläßt, dieser wartet dann und verriegelt die anderen.

1. ist das einfach lockmutex

aber wie bekomme ich das andere hin? mit TryLockMutex(Mutex) klappt es nicht korrekt soweit ich bisher getestet habe. probiere es seit gestern, aber mache jetzt gleich mal weiter, vielleicht komme ich ja noch drauf.

bin also für Tips dankbar.

Gruß
Toshy
Zuletzt geändert von Toshy am 06.02.2006 22:58, insgesamt 1-mal geändert.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Kleiner Beispielcode:

Code: Alles auswählen

enableexplicit

Global Dim names.s(3)
Global NewList queue.s()
Global counter.l, mutex.l
names(0) = "peter"
names(1) = "hans"
names(2) = "franz"
names(3) = "juuli"
mutex = CreateMutex()


Procedure thread(index.l)
  Protected name.s, z.l
  name = names(index)
  
  z = 0
  Repeat
    
    LockMutex(mutex)
      counter + 1
      AddElement(queue())
      queue() = name
    UnlockMutex(mutex)
    Delay(Random(500) + 200)
    
    z + 1
  Until z = 20
EndProcedure


Define.l t
t = CreateThread(@thread(), 0)
t = CreateThread(@thread(), 1)
t = CreateThread(@thread(), 2)
t = CreateThread(@thread(), 3)


Repeat
  LockMutex(mutex)
    ForEach queue()
      Debug queue()
      DeleteElement(queue())
    Next
  UnlockMutex(mutex)
  
  Delay(50)
Until counter = 80

FreeMutex(mutex)
TryLockMutex() wird z. B. so verwendet (ausm Kopf):

Code: Alles auswählen

; im Thread:
changed = #false
repeat
If TryLockMutex(mutex)
  ; änder das was du ändern willst
  changed = #true
else
  ; mach was solange die ressource gebraucht wird -> Wird nicht unter-
  ; brochen mit LockMutex()
EndIf
until changed
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Hatte grad etwas Zeit:

Code: Alles auswählen

Global mutex.l
mutex = CreateMutex()


Procedure test(dummy.l)
  Delay(500)
  
  Protected changed.l
  
  changed = #False
  Repeat
    If TryLockMutex(mutex)
      Debug "Endlich durchgekommen!"
      changed = #True
      UnLockMutex(mutex)
    Else
      Delay(100)
      Debug "Mann! Du blockst mich"
    EndIf
    
  Until changed
EndProcedure


t = CreateThread(@test(), 5)

LockMutex(mutex)
Delay(1000)
; eine Sekunde lang blocken
UnlockMutex(mutex)

WaitThread(t)
FreeMutex(mutex)
Debug "Ende!"
greetz
Remi

edit: nach Freak ausgebessert!
Zuletzt geändert von remi_meier am 06.02.2006 17:07, insgesamt 1-mal geändert.
freak
PureBasic Team
Beiträge: 766
Registriert: 29.08.2004 00:20
Wohnort: Stuttgart

Beitrag von freak »

LockMutex() wartet bis der Mutex frei ist.
TryLockMutex() wartet nicht, sondern gibt 0 zurück wenn der Mutex nicht frei war.

remi_meier:

Nach einem erfolgreichen TryLockMutex() muss auch ein UnlockMutex() stehen,
sonst bleibt er immer im "locked" status. (ist in dem Beispiel egal, sonst aber ungemein wichtig.)
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Stimmt, sry, war wohl ein wenig unvorsichtig... hab noch ein FreeMutex()
hinzugefügt :)
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

TryLockMutex() wird z. B. so verwendet (ausm Kopf):
Code:

; im Thread:
changed = #false
repeat
If TryLockMutex(mutex)
; änder das was du ändern willst
changed = #true
else
; mach was solange die ressource gebraucht wird -> Wird nicht unter-
; brochen mit LockMutex()
EndIf
until changed
Ich hatte gestern noch was getest und zwar, war ich beim testen sehr verwirrt und sehe jetzt klarer. Leider scheint das NICHT zu stimmen was du schreibst. Ich dachte auch das dies so sein soll, aber es ist so das Try.. auch STARTET wenn der code vom normalen LOCK ausgeführt wird. Der unterschied ist, es wird beim aufruf vom Try der normale "lock-thread-code" GESTOPPT. das ist ja an sich toll, hilft aber in den meißten fällen nicht. zwar kann so nicht doppelt etwas beschrieben werden, aber stellt man sich für, thread A beschreibt eine einen listeneintrag (mehrere felder), er wird gestoppt und dann wird dieser eintrag gelöscht. was dann? also es ist nicht so, das der "Try-Code" erst dann ausgeführt wird, wenn der normale code AM ANFANG gestoppt wurde, oder wenn er abgearbeitet wird, sondern SOFORT (mit stoppen des anderen threads).
Das kann so Katastrophen führen und die Funktion wohl in den meißten Fällen nicht zu bebrauchen. Auf jedenfall bei mir in keinem einzigen Fall.

auf jedenfall sah es bisher so aus.
Ist natürlich schwer sowas zu testen
Aber auf Grund eurer Infos teste ich mal, denn ich kann mich ja total irren.

......
so, ne ganze Testzeit später.
....
ich könnte jetzt den Text oben weglöschen, aber so sieht man wie ich es gedacht hatte. Das lag wohl am schlechten Englisch meinerseits wie aber auch an meiner eigenen CSsektun die halt etwas anders arbeitet.
Ich werde zwar jetzt erst recht testen müssen, aber schön zu wissen wie es gemeint ist.
Daher zum voräufigen Abschluß also noch wichtige Punkte:
1. Ich habe mich also total geirrt in der Auffassung der Funktion Try...
2. Großes Danke an euch :-)

Gruß
Toshy
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

@remi_meier

Also da habe ich mich doch zu früh gefreut. von euer erklärung und dem beispiel klang alles super, aber es klappt nicht.
beim beispiel kommt minuten lang (auch ganz zu anfang) nur
"Mann! Du blockst mich"

Trylock ist IMMER null.
auch mal nur zum test
m = CreateMutex()
Debug m
Ergebnis = TryLockMutex(m)
Debug Ergebnis
ist immer null bei mir.
[edit]ich meine deinen Zweiten code, den ersten noch nicht getest.
aber Try gibt bisher bei mir halt IMMER NULL zurück.
Bin ich jetzt blöd oder was?
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Hallo.

Ich bin mir sicher, das ist ein Bug.
Ich dachte ich bin blöd, aber dem ist wohl doch nicht so.

Code: Alles auswählen

OpenConsole()
Global mutex.l 
mutex = CreateMutex() 


Procedure test(dummy.l) 
  Delay(500) 
  
  Protected changed.l 
  
  changed = #False 
  Repeat 
    If TryLockMutex(mutex) 
      PrintN( "Endlich durchgekommen!" )
      changed = #True 
      UnlockMutex(mutex) 
    Else 
      Delay(100) 
      PrintN( "Mann! Du blockst mich" )
    EndIf 
    
  Until changed 
EndProcedure 


t = CreateThread(@test(), 5) 

LockMutex(mutex) 
Delay(1000) 
; eine Sekunde lang blocken 
UnlockMutex(mutex) 

WaitThread(t) 
FreeMutex(mutex) 
Delay(15000)
Debug "Ende!"
CloseConsole()
Ich habe mal zum testen, weil mir hier einiges sehr komisch war diesen Code zur EXE kompiliert und auf meinem Windows XP Rechner laufen lausen. Und oh wunder, der Code läuft, Trylockmutex() funktioniert.
Aber auf meinem Windows 98 Rechner geht es NICHT (kein SE).
Bei Windows 98 funktioniert trylockmutex nicht.
Wie kann das denn sein?
Gruß
Thorsten

[edit]
ach ja, ich weiß natürlich nicht, ob es am unterschiedlichen betriebssytem liegt oder das der Rechner auf dem es geht einen AMD 2400XP besitzt und auf dem es nicht geht ein AMD 1800XP CPU ist.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Bestätigt. Die selbe EXE von mir hat bei einem Freund (Intel CPU`S) auf dem Windows XP funktioniert und auf einem Windows 98SE nicht.
Auf Windows98 und SE geht trylockmutex nicht.


Wann kommt vermutlich die nächste Beta?
Benutzeravatar
MLK
Beiträge: 267
Registriert: 01.11.2004 13:17
Wohnort: Hamburg

Beitrag von MLK »

habe mich vorhin schon gewundert, denn bei mir (win2000) läufts auch :)
Gesperrt