![]() |
Variablenübergabe Createthread verständnisproblem
ahoi
Ich möchte einfach 5 Zahlen/Strings in eine Datei (test.txt) schreiben, wobei jede Zahl/String durch einen eigenen Thread in diese Datei geschrieben werden soll. Hier mein Versuch:
Delphi-Quellcode:
Das Ergebnis in der Datei ist leider immer:procedure TForm1.Button1Click(Sender: TObject); function WriteStringInFile( p: pchar ):integer; stdcall; var f: textfile; begin AssignFile( f, 'test.txt' ); Append(f); writeln( f, p ); CloseFile(f); end; var s: string; i: integer; TID: DWORD; begin for i:=0 to 4 do begin s := IntToStr( i ); TID := 123+i; CreateThread(nil, 0, @WriteStringInFile, pchar(s), 0, tid); end; end; 4 3 4 3 4 Wo liegt mein Fehler? ;) |
Re: Variablenübergabe Createthread verständnisproblem
1: Also erstmal ist dieser Dateizugriff nicht ThreadSave
Append öffnet eine Datei und setzt den Dateizeiger auf das Dateiende. > wenn jetzt zwischen Append und WriteLn ein anderer Thread in die Datei was reingeschrieben hat, dann stimmt die Position nicht mehr, da sich das Dateiende verschiebt, aber der nicht Dateizeiger in f. 2: CreateThread übergibst du einen Zeiger auf den String "S" gehtst dann weiter veränderst den String (für den nächsten Thread) also könnte (und ist mit Sicherheit auch) sobald der Thread bei WriteLn ankommt der Zeiger ungültig. > entweder ist in dem String ein anderer Inhalt (die nächste Zahl) oder noch schlimmer, der String steht inzwischen an einer anderen Speicheradresse und du greifst auf etwas zu, was kein String mehr sein muß. Zitat:
bzw, was willst du mal erreichen... Das Stringproblem kannst du aber leicht umgehn, indem du die Zahl übergibst und im Thread erst in einen String umwandelst.
Delphi-Quellcode:
außerdem muß du den Zugriff auf die Datei noch irgendwie ThreadSicher machen ... z.B. über eine
procedure TForm1.Button1Click(Sender: TObject);
function WriteStringInFile( i: integer ):integer; stdcall; var s: String; f: textfile; begin s := IntToStr(i); {hier Dateizugriff für andere Threads sperren} AssignFile( f, 'test.txt' ); {kannst aber auch erst hier sperren ... Assign öffnet die Datei ja noch nicht} Append(f); writeln( f, s ); // oder einfach nur writeln( f, i ); CloseFile(f); // das wandelt dann sleber intern um {und hier Dateizugriff wieder freigeben} end; var i: integer; TID: DWORD; begin for i:=0 to 4 do begin CreateThread(nil, 0, @WriteStringInFile, i, 0, @tid); // tdi ist ein Ruckgabeparameter ... heißt, da schreibt ChreateThread was rein // und du kannst das auslesen (es wird also nichts an ChreateThread übergeben) end; end; ![]() und wenn/da du dich mit der WinAPI CreateThread nicht so auskennst (wenn ich mir TID anseh) > schau dir mal ![]() PS: außerdem setzt ChreateThread nicht IsMultithreaded auf True und wenn IsMultithreaded auf False steht, dann ist der speicherManager ebenfalls nicht ThreadSave und es könnte noch weitere Probleme geben. |
Re: Variablenübergabe Createthread verständnisproblem
Du übergibst einen Zeiger auf den String. Du kopierst ihn nicht bei der Übergabe. Und jetzt ist die Frage wer schneller ist. Der Thread mit dem Auslesen des Strings oder der MaintThread mit dem ändern. Und wenn der MainThread ändert, ist die Frage, wo kommt der neue String hin und wird der alte Platz überschrieben. Er könnte sogar ungültig werden, wodurch ein AV kommen müsste.
Andere Fehler, die noch kommen könnten: 1. Du öffnest die Datei zum schreiben. Falls ein anderer Thread die Datei noch offen hat, kommt es zum Fehler. Das ist halt Zufall und kann nicht vorhergesagt werden. Vielleicht kommt ein Threa mal beim schreiben ins stocken, weil die Festplatte grad anderweitig zu tun hat.[/Roter Kasten] 2. Nimm statt CreateThread besser BeginThread. Dadurch sagst du dem Speichermanager wenigstens noch Bescheid, dass du Multithreaded arbeitest (Achtung: Dann nicht mehr stdcall). |
Re: Variablenübergabe Createthread verständnisproblem
also ich will schon strings übergeben
die denn in die datei geschrieben werden sollen und jeder String soll in einem eigenen Thread in die datei geschrieben werden die Zahlen waren dabei nur als beispiel gedacht und mit BeginThread schreibt der "kompletten wirrwarr" ;) |
Re: Variablenübergabe Createthread verständnisproblem
Zitat:
Zitat:
In deinem Fall würde ich dann doch zur Klasse TThread greifen. Da hast du dann gleich eine Klasse, in der du den String unterbringen kannst.
Delphi-Quellcode:
Andere Möglichkeit (ohne TThread) wäre, du assoziierst dir Speicher und übergibst den Pointer darauf und gibst den Speicher im Thread frei.
type TWriteFile=class(TThread)
constructor create(s:string); protected procedure execute; override; private Fs:String; end; .... constructor TWritefile.create(s:string); begin Fs:=s; Freeonterminate:=true; inherited create(false); end; procedure TWritefile.execute; begin //Hier jetzt entweder mit CriticalSection oder mit synchronize in Datei schreiben end; procedure TForm1.Button1Click(Sender: TObject); begin ... TWriteFile.create(s); ... end; |
Re: Variablenübergabe Createthread verständnisproblem
jo stdcall ist raus
Ergebnis/WirrWarr ist: , , |
Re: Variablenübergabe Createthread verständnisproblem
Edit oben ;)
Das Wirrwarr entsteht durch die ganz oben genannten Gründe. Du hast vorhin nur Glück gehabt; und vielleicht auch, da Beginthread etwas länger dauert. Aber dein Thread wird ja hoffentlich nicht so kurz bleiben, sonst lohnt er sich ja nicht. Und damit wirst du zu ähnlichen Laufzeitproblemen kommen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:12 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz