Variable als Flag zur Threadsicherheit

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Kaeru Gaman hat geschrieben: aber was auch immer das ist, ich bezweifle einfach mal,
dass es eine ähnlichkeit mit dieser extremen versuchsanordnung hat.
Ich nicht, ich denke es wird schimmer sein :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

:mrgreen: eeGAL!

ich habe nachgewiesen, dass es sich nicht hängt sondern nur schweinelange dauert.
somit ist meine aussage vom anfang gestützt, die verwaltung der globalen counter sei problemlos.

kannst ja mal gucken, wie lange deine 100 threads brauchen...

Code: Alles auswählen

Global glob.l 

Dim Threads.l(99) 

#LastThread = 99 

Procedure Thread(dummy.l) 
  Repeat 
    glob + 1 
  ForEver 
EndProcedure 

Debug "Label 1" 
time = ElapsedMilliseconds() 
For I = 0 To #LastThread
  Debug "starting No. "+Str(I) 
  Threads(I) = CreateThread(@Thread(), 0) 
Next 
time = ElapsedMilliseconds() - time 
Debug time 
Debug "Label 2" 
Delay(5000) 
Debug "Label 3" 
For I = 0 To #LastThread 
  KillThread(Threads(I)) 
Next 
Debug "Label 4" 
Debug glob
have fun! :mrgreen:
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

@remi_meier
Das liest sich, als ob es mehrere Mutexe gibt, es gibt aber doch nur einen für alle Objekte, globalen Variablen usw.
Sonst müßte man ja bei der Erstellung des Mutex angeben, wofür er ist :wink:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Ich erstelle für mehrere Objekte auch mehrere Mutexes?

Code: Alles auswählen

mutex1 = CreateMutex()
mutex2 = CreateMutex()
Debug mutex1
Debug mutex2
Ein Mutex ist eine CriticalSection von Windows.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Und woher weiß mutex1 was er schützen soll, verstehe ich nicht so ganz :oops:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

@Kaeru Gaman
soweit ich das verstanden habe,
geht es toshy um gemeinsamen zugriff auf eine global-steuerung von mehreren threads aus,
und das läuft bei mir problemlos.
Verinfacht gesagt stimmt das wohl so. Zwar muß ich testen, wie es dann mit dem Abfragen des Inhalt und dem damit verbundenen Timing aussieht, aber meine Frage Frage hast du richtig verstanden.

@ts-soft
Bei mir hängt sich das meist auf, und es sind nur 100 Threads, wie ich
Toshy einschätze möchte er mehr erstellen Satisfied Smile
*grins*
Na ja, also ich versuche es natürlich mit so wenig Threads wie möglich, aber es könnte natürlich wirklich zu vielen Threads kommen. Aber es geht ja nicht und die Anzahl, sondern das Prinzip. Möchte logischer Weise solche unnötigen Fehlerquellen ausschließen.

@Kaeru Gaman
egal wie viele threads Toshy verwenden will,
er wird bestimmt nicht hunderte derselben einfachen endloszähler starten wollen.
Normal zwar nicht, aber bei einer Procedure hätte das sogar passieren können, nur habe ich das jetzt erstmal etwas umgeplant. z.B. bei der Verarbeitung von eingehenden Networkdaten die etwas zeitintensiver sind, hätte das vorkommen können. Aber das werde ich nun erst später wenn es notwendig wird einbauen.

@all
Es war ursprünglich also schon so, das die selbe Procedure als Thread ausgeführt werden solle (dutzendfache oder mehr, natürlich nur wenn je gebraucht). Eingehende Daten (z.B. Netzwerk) müsten Zeitintensiv (also länger als nur 5 oder 10ms) verarbeitet werden, die jeweiligen Daten werden dann aus einer "Liste" rausgeholt und von einem freien Thread (der wartet) verarbeitet, ob nun ein Thread nur einen oder mehrere "Listeneinträge" abarbeitet weiß ich noch nicht. Nun aber geht es nur um einige (erstmal 2-4 Threads) die so unabhängig wie möglich sind, um keine wartezeiten auszulösen (wie bei Mutex), dazu nutze ich Flags die ihn ihrer Nutzung aber sicher sind (insoweit das hier geklärte zutriff).
Dabei ging es mir in erster Linie natürlich darum, das es nicht zu Abstürzen oder fehlerhaften Ergebnissen kommt. Das sogar die Berechnung nacheinander ausgeführt wird, ist ein angenehmer Nebeneffekt, daß alles etwas einfacher macht, da man direkt nach dem setzen der Daten in einem Thread diese mit einem anderen auslesen kann ohne das die Daten vielleicht noch nicht "ganz berechnet" wurden.

Da ich gerade so einen Teil bearbeite nehme ich das also als Beispiel:
Da ich nun von vielen Clienten Daten empfange, diese in einen Buffer schreiben muß und dann ständig überprüfen muß was an Daten da sind um sie ab einem bestimmten Zeitpunkt zu bearbeiten, geht das nur sinnvoll mit Threads. Dabei schreibt z.B. ein Haupthread die Networkdaten in einen Speicherbereich, ein anderer Thread lies und überprüft diese und bei bedarf löscht er diese. Natürlich kann es dazu kommen, das wenn zwei Thread gleichzeitig auf diesen Bereich zugreifen, dies fehlschlägt, weil ein neuer Speicherbereich allokiert wurde.
Erstelle ich nun z.b. dafür immer wieder ein Mutex gibt es ähnliche Probleme wie beim erstellen von Threads, es dauert einfach so lang, das der ZEitgewinn durch die Threadverarbeitung mehrfach wieder dahin gerafft wird. Also muß ich es auf eine einfach und schnelle Weise machen und das geht mit einfachen Variablen (am besten in Strukturen) am besten.
Das liest sich, als ob es mehrere Mutexe gibt, es gibt aber doch nur einen für alle Objekte, globalen Variablen usw.
Sonst müßte man ja bei der Erstellung des Mutex angeben, wofür er ist
NAtürlich gibt es mehrer, so wie bereits remi_meyer schrieb. Deshalb muß man auch dolle aufpassen, das man da die Struktur gut aufbaut, sonst hängt man selbst sein Programm unwiederbringlich auf. hehe. das macht so richtig Spaß so einen Mutexstrukturfehler zu finden.
1. Win10
PB6.1
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

@ts-soft
soweit ich weiß, weiß er nur eines "ich bin gemeint".
Beim erstellen des Mutex erhält man ja einen Wert, die MutexID, beim Sperren / Aufruf mit LockMutex(Mutex) muß man diese ID ja angeben. Jeder Thread der nun diese MutexID abfragt bleibt stehen, nur der erste Aufruf kommt durch. Es geht dann für den nächsten Thread erst weiter wenn der Erste ihn freigibt.
Erstellt man einen anderen Mutex mit einer anderen "ID", so werden Abfragen für diesen natürlich nur durchgeführt, wenn auch diese ID angegeben wird. Es gibt also mehrer unabhängige Mutex(mehrzahldinger;-)

Gruß
Toshy
Zuletzt geändert von Toshy am 25.01.2007 15:48, insgesamt 1-mal geändert.
1. Win10
PB6.1
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

also.. noch mal weiter rumgetestet...

das hauptproblem ist die auslastung.
eigentlich kein wunder, dass wenig CPU zur verfügung steht,
um die schleife im Hauptprogramm zu verarbeiten,
wenn schon x threads laufen, die die CPU unter Volllast setzen.

Code: Alles auswählen

Label 1
starting No. 0
starting No. 1
starting No. 2
...
starting No. 99
1811250
Label 2
Label 3
Label 4
-1600444093
wie man sieht, hat das starten der threads ne halbe stunde gebraucht.

mit einer winzigen veränderung

Code: Alles auswählen

Procedure Thread(dummy.l) 
  Repeat 
    glob + 1
    Delay(0) 
  ForEver 
EndProcedure 
sieht das schon ganz anders aus:

Code: Alles auswählen

Label 1
starting No. 0
starting No. 1
starting No. 2
...
starting No. 99
47
Label 2
Label 3
Label 4
8756447
sogar mit Delay(0) geht der aufwand auf 1/20 sec runter,
mit Delay(1) ist die zeitangabe dann 0

also eindeutig:
das problem besteht dann, wenn mehrere threads auf Volllast laufen wollen.

@Toshy
bau also am besten in zeitintensive schleifen ein Delay(0) ein,
damit sich deine threads nicht gegenseitig zu sehr bremsen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag von remi_meier »

Vielleicht ist es so einfacher zu verstehen:

Code: Alles auswählen

Procedure.l MutexCreate()
  Protected *p = AllocateMemory(SizeOf(CRITICAL_SECTION))
  If *p
    InitializeCriticalSection_(*p)
  EndIf
  ProcedureReturn *p
EndProcedure

Procedure MutexFree(Mutex.l)
  If Mutex
    DeleteCriticalSection_(Mutex)
    FreeMemory(Mutex)
  EndIf
EndProcedure

Procedure MutexLock(Mutex.l)
  EnterCriticalSection_(Mutex)
EndProcedure

Procedure.l MutexTryLock(Mutex.l)
  ProcedureReturn TryEnterCriticalSection_(Mutex)
EndProcedure

Procedure MutexUnLock(Mutex.l)
  LeaveCriticalSection_(Mutex)
EndProcedure
Wenn man ein Objekt schützen möchte, erstellt man für dieses Objekt
eine CriticalSection. Will man nun Zugriff auf dieses Objekt erhalten,
betritt man diese Critical Section (EnterCriticalSection_() bzw. LockMutex()).
Man ist nun der einzige Thread in dieser CS und kann mit dem geschützten
Objekt alles machen, was man will. Dann verlässt man diese CS wieder.
Natürlich kann man so viele CS machen, wie man will. Eine CS stellt einfach
sicher, dass man der einzige Thread in dieser CS ist.
Wenn man ein Objekt schützen will, darf man es einfach nur in einer
CS manipulieren. Ausserhalb einer CS wäre das Objekt ungeschützt und
mehrere Threads könnten gleichzeitig das Objekt manipulieren.
Antworten