Win10, Matlab/CMD: Programmaufruf in CMD vorzeitig beenden

Scientist

Lt. Commander
Registriert
Apr. 2018
Beiträge
1.133
Hallo zusammen

Hintergrund:
Über Matlab rufe ich in einer parallerisierten for-Schleife mit System("Simulations.exe >output.txt") einige tausend Mal eine externe Simulation.exe über die CMD auf. Eine Simulation benoetigt dabei ca. 3 bis 8 Sekunden.
Außer der Umleitung des Outputs in eine Datei, werden keine weiteren Befehle an die CMD oder das Programm uebergeben (Austausch erfolgt ueber Textdateien).
Ohne die Umleitung verdoppeln sich die Ausfuehrungszeit.

Problem:
Die Simulation.exe rennt leider in einigen seltenen und unbekannten Faellen in eine Endlosschleife.

Gesucht:
Ich suche also eine Moeglichkeit, ein Programm ueber CMD, Batch, Powershell oder Matlab, ohne zeitverlust auszufuehren, mit der Bedingung es zwangsweise nach einer festen Zeit zu beenden. Idealerweise mit einer eindeutigen Rueckmeldung, wenn es vorzeitig beendet wurde.
Dabei muss der Output der Simulation.exe in eine Datei umgeleitet werden (enthaelt moegliche Fehlermeldungen).
Der Aufruf soll komplett im Hintergrund ablaufen.


In Matlab gibt es zwar die Moeglichkeit, den Befehl asynchron aufzurufen, aber eine anschließende Ueberwachung des CMD-Prozesses halte ich aber nicht fuer sinnvoll, weil er Zeit und Ressourcen kosten wuerde.
Allerdings habe ich auch nicht herausfinden koennen, wie ich an die passende PID komme, falls ich den Prozess beenden muesste.


Entsprechend die Frage, ob jemand von euch vielleicht eine Idee hat, wie man bzw. ob man ein Programm ueber Batch/Powershell mit entsprechenden Bedinungen aufrufen kann.
 
Keine Ahnung, wie weit in Matlab einpflegbar:

So kann per Batch der Editor geöffnet und nach 10 Sekunden (10 Pings) geschlossen werden:
Code:
@echo off
start "" "C:\Windows\System32\notepad.exe"
ping 127.0.0.1 -n 10
taskkill /F /IM "notepad.exe"

So in Dauerschleife + schreiben in Logdatei mit Datum und Uhrzeit:
Code:
@echo off
:ANFANG
start "" "C:\Windows\System32\notepad.exe"
ping 127.0.0.1 -n 2
taskkill /F /IM "notepad.exe" >> C:\tmp\Logfile.txt 2>&1
echo %DATE% >> C:\tmp\Logfile.txt 2>&1
echo %TIME% >> C:\tmp\Logfile.txt 2>&1
echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX >> C:\tmp\Logfile.txt 2>&1
GOTO ANFANG
 
  • Gefällt mir
Reaktionen: BAGZZlash
@ryan_blackdrago
Danke fuer deine Antwort, das hilft mir schon ein Stueck weiter,
aber "notepad.exe" kann ich bei taskkill nicht verwenden, weil dadurch alle bestehen "notepad.exe"-Prozesse beendet werden und nicht eine bestimmte, die ueber diesen Befehl aufgerufen wurde.

Liese sich die PID des gestarteten Prozess irgendwie bestimmen?
 
Solche Beispiele sind eigentlich recht einfach in einer Suchmaschine auffindbar..

Beispiel aus dem Suchmaschinen-Fund + umgemünzt auf die obigen Beispiele:
Code:
@echo off
set AppCmdLine="C:\Windows\System32\notepad.exe"
set ProcessCmd=wmic process call create %AppCmdLine%
for /f "tokens=3 delims=; " %%a in ('%ProcessCmd% ^| find "ProcessId"') do set PID=%%a
ping 127.0.0.1 -n 5
taskkill /PID %PID%

Code:
@echo off
:ANFANG
set AppCmdLine="C:\Windows\System32\notepad.exe"
set ProcessCmd=wmic process call create %AppCmdLine%
for /f "tokens=3 delims=; " %%a in ('%ProcessCmd% ^| find "ProcessId"') do set PID=%%a
ping 127.0.0.1 -n 5
taskkill /PID %PID% >> C:\tmp\Logfile.txt 2>&1
echo %DATE% >> C:\tmp\Logfile.txt 2>&1
echo %TIME% >> C:\tmp\Logfile.txt 2>&1
echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX >> C:\tmp\Logfile.txt 2>&1
GOTO ANFANG
 
  • Gefällt mir
Reaktionen: Scientist
Sry, dass ich erst jetzt eine Rueckmeldung gebe ...
Mit wmic wurde die Simulation nicht ausgefuehrt. Ursache unklar.

Zum Testen hatte ich dann folgenden Code probiert.
Code:
@echo off
start "UniqueWindowTitle" cmd /c "C:\Simulation\Simulation.exe >out.txt"
ping 127.0.0.1 -n 5
taskkill /fi "WINDOWTITLE eq UniqueWindowTitle" 2>nul

Der Aufbau fuehrt aber nicht zum gewuenschten Ziel.
Wenn ich die Batch-Datei ueber Matlab aufrufe, gibt es erst eine Rueckmeldung, wenn auch ping durch ist (und es oeffnen sich 2 Fenster ...).
Das Ziel ist jedoch: Rueckmeldung, wenn Simulation durch oder Zeit x ueberschritten.
Je nachdem, was zuerst eintrifft.

Also muessen im Prinzip die Befehle umgedreht werden ...

Entsprechend rufe im ueber Matlab die Batch wie folgt auf:
Code:
start "UniqueWindowTitle" cmd /c start_Sim.bat

Vorteil, ich kann ueber Matlab eine einmalige Bezeichnung vergeben.

In der Batchdatei wird dann im separaten Prozess taskkill verzoegert gestartet und dann die Simulation aufgerufen.
Code:
@echo off
start "" cmd.exe /c "timeout 10 & taskkill /fi "WINDOWTITLE eq UniqueWindowTitle" 2>nul"
C:\VHP_Simulation\VHP_Sim2\vapour_x.exe >out.txt

Offene Punkte:
  • uebergebenen Titel in Batch auslesen und Taskkill uebergeben
  • Fenster der Batch und von taskkill unterdruecken
 
Der Code enthält Denkfehler:
Code:
@echo off
start "UniqueWindowTitle" cmd /c "C:\Simulation\Simulation.exe >out.txt"
ping 127.0.0.1 -n 5
taskkill /fi "WINDOWTITLE eq UniqueWindowTitle" 2>nul
-mit cmd /c wird in der CMD ein weiteres CMD-Fenster geöffnet => daher existieren auch zwei CMD-Fenster
-taskkill UniqueWindowTitle schließt das Fenster mit UniqueWindowTitle und nicht wie gewünscht die Simulation.exe
-auch die Parameterübergabe an die Simulation.exe müsste geprüft werden.

Code:
@echo off
start "" "C:\tmp\simulation.exe" "whatever parameter"
ping 127.0.0.1 -n 5
taskkill /f /im "simulation.exe"

//Edit:
die Beispiele aus Post#4 wurden schätzungsweise auch mit cmd /c eingepflegt?
Dies funktioniert bei mir:
Code:
@echo off
set AppCmdLine="C:\tmp\simulation.exe whatever parameter"
set ProcessCmd=wmic process call create %AppCmdLine%
for /f "tokens=3 delims=; " %%a in ('%ProcessCmd% ^| find "ProcessId"') do set PID=%%a
ping 127.0.0.1 -n 5
taskkill /PID %PID%
 
Zuletzt bearbeitet:
Code:
@echo off
start "UniqueWindowTitle" cmd /c "C:\Simulation\Simulation.exe >out.txt"
ping 127.0.0.1 -n 5
taskkill /fi "WINDOWTITLE eq UniqueWindowTitle" 2>nul

Ja, dieser Code schließt das Fenster, damit wird aber auch die Simulation.exe beendet.
Also funktioniert das fuer mich.

Ich hab es trotzdem auf die PID wieder umgestellt.

Der Aufruf erfolgt jetzt mit
Code:
start "" kill_sim.bat & Simulation.exe > out.txt

Dabei sieht die kill_sim.bat so aus:
Code:
@echo off

for /f "tokens=1,2" %%i in ('wmic process where "name='Simulation.exe'" get ProcessID^, ExecutablePath') do ^
if "%%i" == "%~dp0Simulation.exe" (set pidnr=%%j)

timeout 10
::ping 127.0.0.1 -n 10

for /f "tokens=1,2" %%i in ('wmic process where "name='Simulation.exe'" get ProcessID^, ExecutablePath') do ^
if "%%i" == "%~dp0Simulation.exe" (set pidnr_check=%%j)

if %pidnr% == %pidnr_check% (taskkill /F /pid %pidnr_check%)

Nach Aufruf der Batch, wird die PID ueber den Unterordner bestimmt und nach der festgelegten Zeit beendet, sofern er noch immer aktiv ist.

Bisher habe ich aber noch nicht herausgefunden, wie ich bei "start" das Fenster der Batch unterdruecken kann. "start /b" funktioniert an dieser Stelle.

Damit rufe ich aus Matlab die Batch so auf und kein Fenster ploppt auf \o/
Code:
start /b "" kill_sim.bat & Simulation.exe > out.txt


Vielen Dank ryan_blackdrago fuer deine Anregungen.
 
Zuletzt bearbeitet:
Was ist eigentlich mit ner "nativen" Matlab-Lösung?
Code:
process = java.lang.Runtime.getRuntime().exec('cmd');
out = process.getOutputStream();
out.write(uint8('text'));
out.close();
process.waitFor(10,java.util.concurrent.TimeUnit.valueOf('SECONDS'));
Vorteil: Komplett asynchron, also auch N Prozesse parallel. Du könntest mit getInputStream() auch die Ausgabe des Prozesses mitlesen und darauf reagieren. Mit process.destroy() wirst du ihn wieder los.

EDIT: Relevante Doku: Process (Java Platform SE 8 ) (oracle.com) TimeUnit (Java Platform SE 8 ) (oracle.com)
 
  • Gefällt mir
Reaktionen: Scientist
Mithilfe dieser Simulation will ich eine Optimierung durchfuehren.
Je Optimierungsschritt sind jedoch x Simulationen notwendig. Die Anzahl x ist dabei aber groeßer, als die Anzahl der parallelen Aufrufe der Simulation. Das ganze wird mit parfor (parallele for-Schleife) abgearbeitet.
Bsp.: 50 Simulationen muessen je Schritt durchgefuehrt werden, aber aufgrund der PC-Auslastung werden nur 10 parallel ausgefuehrt.
Die Kommunikation mit der Simulation.exe erfolgt rein auf Textdateien (Input und relevanter Output). Die Infos, die mir dabei ins CMD geworfen werden, sind bis auf Fehlermeldungen unbrauchbar.
Und aus zeitlichen Gruenden, muss der CMD-Output in eine Datei geleitet werden.

Ein asynchroner Funktionsaufruf aus Matlab heraus wuerde bedeuten, das ich die angestoßenen Prozesse Ueberwachung muesste, damit ich die Ergebnisse anschließend aus den Textdateien einlesen kann.
Ich halte es fuer sinnvoller, dass der angestoßene Prozess sich selbst meldet, damit kein zeitverlust eintritt.
Ob es das auch ist: keine Ahnung.

Der asynchrone Aufruf erscheint mir aber mehr Fehlerpotential zu bieten und spontan wuesste ich auch nicht, wie ich die Aufrufe sinnvoll parallerisieren sollte.
 
Na ja
Code:
for i=1:N
process{i}=java.lang.Runtime.getRuntime().exec('cmd /c simulation.exe > nul 2>nul');
end
sleep(10);
for i=1:N
if process{i}.isAlive()
process{i}.destroyForcefully();
end
end
führt N Prozesse parallel aus, kein parfor, und die Prozesse, die nach 10 s nicht fertig sind, werden gekillt. Du kannst das natürlich in parfor packen
Code:
parfor i=1:N
process=java.lang.Runtime.getRuntime().exec('cmd /c simulation.exe > nul 2>nul');
sleep(10);
if process.isAlive()
process{.destroyForcefully();
disp([num2str(i) ' killed']);
else
disp([num2str(i) ' success']);
end
end
Aber wenn es funktioniert, never touch a running system.
 
  • Gefällt mir
Reaktionen: Scientist
Dein Batch-Skript schläft auf jeden Fall für ein paar Sekunden. Klar, das ist nicht der Matlab-Thread, aber trotzdem ist da Schlafen dabei. Wie findest du eigentlich raus, wann deine Simulationen zu Ende sind? Polling?

Ich denke halt an eine Lösung wie sowas:
Code:
function execute_multiple(cmdlines,max_parallel,timeout)
    currently_running=struct('process',{},'cmdline',{},'starttime',{});
    while ~isempty(cmdlines)||~isempty(currently_running)
        if numel(currently_running)<max_parallel && ~isempty(cmdlines)
            % Start a task
            currently_running(end+1).process=java.lang.Runtime.getRuntime().exec(['cmd /c ' cmdlines{1} ' >nul 2>nul']);
            currently_running(end).cmdline=cmdlines{1};
            currently_running(end).starttime=clock();
            cmdlines(1)=[];
        else
            did_something=false;
            for i=1:numel(currently_running)
                if currently_running(i).process.isAlive()
                    if etime(clock(),currently_running(i).starttime)>timeout
                        currently_running(i).process.destroy();
                        currently_running(i)=[];
                        did_something=true;
                        break;
                    end
                else
                    currently_running(i)=[];
                    did_something=true;
                    break;
                end
            end
            if ~did_something
                pause(0.1);
            end
        end
    end
end

Aber das artet genauso aus wie deine Batch, bloß halt in Matlab-Code... Von dem her, never touch a running system.
 
  • Gefällt mir
Reaktionen: Scientist
Nein, kill_sim.bat wird parallel und unabhaengig zur Simulation aufgerufen.
Wenn also die Simulation durch ist, bekommt Matlab die entsprechende Rueckmeldung.
Entsprechend habe ich hier kein zeitverlust.

Ja, das ist richtig ... man muesste permanent alle Prozesse ueberwachen und den naechsten starten, wenn einer durch ist.
Das einsparen der parfor-Schleife wuerde zwar etwas Ressourcen sparen (und eine Toolbox), aber nicht ausreichend, um eine weitere Simulation laufen zu lassen. Die Frage ist auch, wie viel das Ueberwachen kostet.

Linux, Mac oder "keine parfor" ist aktuell auch keine Anforderung.

Theoretisch liese sich meine Loesung sicherlich auch in komplett in Matlab umsetzen.
Meine Loesung ist vielleicht auch nicht wirklich zuverlaessig, muss sich noch zeigen.

Danke dir jedenfalls fuer den alternativen Weg.
Vielleicht wird er in Zukunft noch mal relevant oder bei einem anderen Problem.
Mit Java habe ich unter Matlab bisher nichts gemacht.
 
Zurück
Oben