Daten in Speicher zwischen Threads übergeben

Anfängerfragen zum Programmieren mit PureBasic.
nalor
Beiträge: 10
Registriert: 29.06.2009 15:48

Daten in Speicher zwischen Threads übergeben

Beitrag von nalor »

Hallo!
Habe ein Programm mit mehreren Threads - einer davon ist mein "Druck-Thread" und die Daten, die gedruckt werden sollen möchte ich einfach als Speicherbereich übergeben.

Aktuell habe ich es so gelöst, das ich den Pointer auf den Speicher einfach in eine Liste schreibe und die Adresse im anderen Thread wieder auslese und dann dort auch den Speicher wieder freigebe.

Habe hier mal ein kurzes Beispiel zusammengeschustert:

Code: Alles auswählen

Structure TestList
	*MemAddress
	sName.s
EndStructure

Global TestSem=CreateSemaphore()
Global TestMutex=CreateMutex()
Global NewList TestFileList.TestList()

Global iCloseAllThreads.i=0
Global CloseMutex=CreateMutex()

Procedure.i ReadFileThread(*Wert)
	Protected iHelp.i, iSize.i, *FileData, iCloseThread.i=0

	While (iCloseThread=0)

		LockMutex(CloseMutex)
		iCloseThread=iCloseAllThreads
		UnlockMutex(CloseMutex)

		iHelp=ReadFile(#PB_Any, "C:\Users\roland\Desktop\print.txt")
	
		If iHelp
			iSize = Lof(iHelp)
			*FileData = AllocateMemory(iSize)
			ReadData(iHelp, *FileData, iSize)
			CloseFile(iHelp)
	
			LockMutex(TestMutex)
			
			LastElement(TestFileList())
			AddElement(TestFileList())
			TestFileList()\MemAddress=*FileData
			TestFileList()\sName=Str(ElapsedMilliseconds())
			UnlockMutex(TestMutex)
			SignalSemaphore(TestSem)
	
		EndIf	
		Delay(2000)
	Wend
EndProcedure

Procedure.i WriteFileThread(*Wert)

	Protected iHelp.i, iSize.i, iCloseThread.i=0

	While (iCloseThread=0)

		LockMutex(CloseMutex)
		iCloseThread=iCloseAllThreads
		UnlockMutex(CloseMutex)

 		If TrySemaphore(TestSem)
 		
	 		LockMutex(TestMutex)
	 		
	      While FirstElement(TestFileList())<>0 ;solange ein erster eintrag existiert
	      
				iHelp=CreateFile(#PB_Any, "C:\Users\roland\Desktop\thread_test\print_write"+TestFileList()\sName+".txt")
			
				If iHelp
					iSize = MemorySize(TestFileList()\MemAddress)
					WriteData(iHelp, TestFileList()\MemAddress, iSize)
					CloseFile(iHelp)
			
					FreeMemory(TestFileList()\MemAddress)
					FirstElement(TestFileList())
					DeleteElement(TestFileList())
				EndIf
	      Wend
	 		UnlockMutex(TestMutex)
	 	Else
	 		Delay(500)
	 	EndIf

	Wend

EndProcedure

OpenConsole()

Define iThread1.i, iThread2.i

	PrintN("threads werden gestartet")
	
	iThread1=CreateThread(@ReadFileThread(), #Null)
	iThread2=CreateThread(@WriteFileThread(), #Null)

	PrintN("mit ESC beenden")

		Repeat
			KeyPressed$ = Inkey()	
			Delay(10)
		Until KeyPressed$ = Chr(27) ; Wartet, bis Escape gedrückt wird
CloseConsole()
Also in meinem Beispiel funktioniert es mal gut - aber in meinem echten Programm bekomme ich an den seltsamsten Stellen IMAs bzw. endet es wieder mal unerwartet, ... und ich denke es könnte mit diesem Konstrukt der Datenübergabe zusammenhängen.

Macht mein Beispiel Sinn oder ist das komplett verkehrt? Wie kann man es besser machen? Die Datenmenge ist ja nicht fix - daher brauche ich einfach einen dynamischen Weg der Datenübergabe.. bin für alle Ideen offen.

Danke!

Roland
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Daten in Speicher zwischen Threads übergeben

Beitrag von STARGÅTE »

So wie ich das auf den ersten Blick sehe, hast du alle Sachen gut abgesichert. (LinkedList, Variablen, usw.)

Das einzige was ich nun vermute ist, das du vergessen hast eine Thread-sichere Exe zu erstellen.
Das sollte man immer machen, wenn man in Threads Strings verwendet, unabhängig davon ob sie sich überkreuzen.

Und du verwendest ja an mehrer Stellen "kleinere" strings.

Ein schnelles einfaches Beispiel zeigt es, wie unsicher es wäre:

Code: Alles auswählen

Procedure test(Null=#Null)
 Repeat
  Delay(0)
  LOL$ = Str(Random($7FFFFFFF))
 ForEver
EndProcedure

For n = 1 To 2
 CreateThread(@test(), 0)
Next

Delay(10000)
Eigentlich nichts aufregendes. Trotzdem komms nach wenigen Millisekunden zu:
[ERROR] Zeile: 4
[ERROR] Ungültiger Speicherzugriff. (Schreibfehler an der Adresse 4294967263)
Zeile 4 : Str(Random($7FFFFFFF))

Das wäre sowas ähnliches wie dein :Str(ElapsedMilliseconds())

schalte ich nun Thread-sichere Exe ein, läufts, weil dann eine andere (langsammere, dafür sicherere) String-Lib benutzt wird.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
nalor
Beiträge: 10
Registriert: 29.06.2009 15:48

Re: Daten in Speicher zwischen Threads übergeben

Beitrag von nalor »

Mein Fehler war einer ganz anderen Stelle... hatte mir eine kleine Prozedur geschrieben die ein paar Bytes im Speicher verschiebt und irgendwie war die da mit dran Schuld - nachdem ein MoveMemory die ganze Sache aber einfach erledigt habe ich kleine Prozedur in die ewigen Jagdgründe geschickt und schon funktionierts :)

Die Option Thread sicheres Executable hatte ich vorher schon angehakt - aber das wars leider noch nicht :(

Trotzdem Danke für die Hilfe!

mfg, Roland
Antworten