2016-07-09 10 views
-3

Ich habe ein Problem mit der Anzahl der Iterationen in Tparallel.for. Ich habe 100 Ordner und in jedem Ordner existiert eine Datei zu laufen (run.bat). Nach dem Ausführen der out.txt-Datei wird im Ordner erstellt.Wenn ich Tparalle.for mit 100 Iterationen verwenden, erhalte ich zufällig 90 bis 98 out.txt, während es 100 sein. mein Code ist wie folgt (Delphi XE7):Verwenden von SetCurrentDir und WinExec32AndWait innerhalb TParallel.For überspringt einige Iterationen

TParallel.For(1, 100, procedure(i: integer) 
    begin 
     SetCurrentDir(path + '\test\' + IntToStr(i)); 
     WinExec32AndWait(PChar('run.bat'), 0); 
    end); 
+0

Sorry, aber ich verstehe nicht, was ist das Problem? Was erwartest du und was ist das wirkliche Ergebnis? Vielleicht auch gerne zu sehen: http://StackOverflow.com/Help/Artikel – Andrej

Antwort

3

Das Prozessarbeitsverzeichnis ist ein einzelner Wert für den Prozess. Sie erwarten, dass jede Aufgabe ihre eigene private Kopie hat, aber so funktioniert das Arbeitsverzeichnis einfach nicht. Technisch gesehen gibt es ein Datenrennen im geteilten prozessweiten Arbeitsverzeichnis. Aufgrund dieser Rasse, wenn die Kindprozesse erstellt werden, erben sie das Arbeitsverzeichnis des Elternteils, aber aufgrund der Rasse erben einige Kinder das Arbeitsverzeichnis, das für verschiedene Kinder vorgesehen ist. Dies ist einer der klassischen Fehler bei der parallelen Programmierung.

Damit umgehen Sie die Verwendung des Arbeitsverzeichnisses des übergeordneten Prozesses. Modifiziere es überhaupt nicht. Übergeben Sie stattdessen das Arbeitsverzeichnis an jeden untergeordneten Prozess, während Sie sie erstellen. Dies kann ganz einfach unter Verwendung von CreateProcess oder ShellExecuteEx erfolgen. Ihre WinExec32AndWait Funktion muss möglicherweise geändert werden, um ein Arbeitsverzeichnisargument zu akzeptieren.

Dies löst das Problem, indem sichergestellt wird, dass Sie für jeden untergeordneten Prozess eine separate Kopie des Arbeitsverzeichnisses erstellen.

+0

WinExec32AndWait Funktion ist wie folgt: – AMIR

+0

Funktion WinExec32AndWait (const Cmd: Zeichenfolge; const CmdShow: Integer): Cardinal; var StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; beginnen Ergebnis: = Cardinal ($ FFFFFFFF); FillChar (StartupInfo, SizeOf (TStartupInfo), # 0); – AMIR

+0

StartupInfo.cb: = SizeOf (TStartupInfo); StartupInfo.dwFlags: = STARTF_USESHOWWINDOW; // STARTF_USESHOWWINDOW // NORMAL_PRIORITY_CLASS; StartupInfo.wShowWindow: = CmdShow; – AMIR

0

setcurrentdir ist natürlich nicht Multithread! Was ist, wenn 2 Threads gleichzeitig das aktuelle Verzeichnis auf xxx setzen? :)

tun statt

Tparallel.for(1,100.procedure(i:integer) 
begin 
    winexec32andwait(pchar(path+'\test\'+inttostr(i) + '\run.bat'),0); 
end); 
+0

Wahrscheinlich muss das Arbeitsverzeichnis in den untergeordneten Prozess auch –

+0

setzen, wenn winexec32andwait ohne verwenden setcurrentdir, run.bat-Datei wird nicht ausgeführt. – AMIR

+0

@AMIR SetCurrentDir legt das ** globale ** aktuelle Verzeichnis für den aktuellen Prozess fest. Danach starten Sie den Prozess mit dem Batch. Sie vergessen den Multithreading-Aspekt. task1 setze das aktuelle Verzeichnis, task2 setze das aktuelle Verzeichnis, task1 startet den Stapel (oops, auf falsches aktuelles Verzeichnis) - das ist dein Problem –