Description
In this test GAMS jobs are started asynchronous. Afterwards it is demonstrated how to either wait for completion or send a kill signal to those jobs. There are three ways to start a job asynchronously: > $call.Async ... > Execute.ASync '...'; > put_utility fx 'Exec.ASync' / '...'; / put_utility fx 'Shell.ASync' / '...'; After each of those the function JobHandle could be used to get the Process ID of the last job executed. With JobStatus(pid) one could check for the status of a job. Possible return values are: 0: error (input is not a valid PID or access is denied) 1: process is still running 2: process is finished with return code which could be accessed by errorlevel 3: process not running anymore or was never running, no return code available With JobTerminate(pid) a interrupt signal can be send to a running job. If this was successful the return value is one, otherwise it is zero. With JobKill(pid) a kill signal can be send to a running job. If this was successful the return value is one, otherwise it is zero. Contributor: L. Westermann
Small Model of Type : GAMS
Category : GAMS Test library
Main file : asynexec.gms
$title Test asynchronous execution at compile and execution time (ASYNEXEC,SEQ=515)
$onText
In this test GAMS jobs are started asynchronous. Afterwards it is demonstrated
how to either wait for completion or send a kill signal to those jobs. There are
three ways to start a job asynchronously:
> $call.Async ...
> Execute.ASync '...';
> put_utility fx 'Exec.ASync' / '...'; / put_utility fx 'Shell.ASync' / '...';
After each of those the function JobHandle could be used to get the Process ID
of the last job executed. With JobStatus(pid) one could check for the status of
a job. Possible return values are:
0: error (input is not a valid PID or access is denied)
1: process is still running
2: process is finished with return code which could be accessed by errorlevel
3: process not running anymore or was never running, no return code available
With JobTerminate(pid) a interrupt signal can be send to a running job. If this
was successful the return value is one, otherwise it is zero.
With JobKill(pid) a kill signal can be send to a running job. If this was
successful the return value is one, otherwise it is zero.
Contributor: L. Westermann
$offText
$call gamslib -q trnsport
$onEcho > sleep.gms
$if not set secs $set secs 0
display$sleep(%secs%) 'Sleep %secs% seconds'
$offEcho
$call.Async gams sleep --secs 3 lo=%GAMS.lo%
$eval jh JobHandle
$set jh2 %system.JobHandle%
$if not %jh% == %jh2% $abort JobHandle <> system.JobHandle
$log >>> JobHandle : %jh%
$label loopstart1
$eval status JobStatus(%jh%)
$log >>> Status : %status%
$if not %status% == 1 $goTo loopdone1
$call sleep 1
$goTo loopstart1
$label loopdone1
$if not %status% == 2 $abort '*** $call.Async gams... failed: wrong status'
$if errorlevel 1 $abort '*** $call.Async gams... failed: wrong errorlevel'
$call.Async =gams sleep --secs 3 lo=%GAMS.lo%
$eval jh JobHandle
$log >>> JobHandle : %jh%
$label loopstart2
$eval status JobStatus(%jh%)
$log >>> Status : %status%
$if not %status% == 1 $goTo loopdone2
$call sleep 1
$goTo loopstart2
$label loopdone2
$if not %status% == 2 $abort '*** $call.Async =gams... failed: wrong status'
$if errorlevel 1 $abort '*** $call.Async =gams... failed: wrong errorlevel'
file fx;
scalar jh,kill,status /1/;
Execute.ASync 'gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
abort$(status <> 2) '*** Execute.ASync gams... failed: wrong status';
abort$errorlevel '*** Execute.ASync gams... failed: wrong errorlevel';
Execute.ASync '=gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
status = 1;
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
abort$(status <> 2) '*** Execute.ASync =gams... failed: wrong status';
abort$errorlevel '*** Execute.ASync =gams... failed: wrong errorlevel';
put_utility fx 'Exec.ASync' / 'gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
status = 1;
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
abort$(status <> 2) '*** Exec.ASync gams... failed: wrong status';
abort$errorlevel '*** Exec.ASync gams... failed: wrong errorlevel';
put_utility fx 'Shell.ASync' / 'gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
status = 1;
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
abort$(status <> 2) '*** Shell.ASync gams... failed: wrong status';
abort$errorlevel '*** Shell.ASync gams... failed: wrong errorlevel';
$call.Async =gams sleep --secs 3 lo=%GAMS.lo%
$eval jh JobHandle
$log >>> JobHandle : %jh%
$eval status JobStatus(%jh%)
$log >>> Status : %status%
$eval kill JobKill(%jh%)
$log >>> Kill RC : %kill%
$if %kill% == 0 $abort '*** compile time JobKill failed: kill returns error'
$eval status JobStatus(%jh%)
$log >>> Status : %status%
$ifThen %status% == 1
$call sleep 1
$eval status JobStatus(%jh%)
$log >>> Status : %status%
$endIf
$if %status% == 1 $abort '*** compile time JobKill failed: process not killed'
Execute.ASync '=gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
put_utility fx 'log' / '>>> JobHandle :' jh;
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
kill = JobKill(jh);
put_utility fx 'log' / '>>> Kill RC :' kill;
abort$(kill=0) '*** execution time JobKill failed: kill returns error';
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
if(status=1,
display$sleep(1) 'sleep some';
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
);
abort$(status=1) '*** execution time JobKill failed: process not killed';
Execute.ASync 'gams sleep --secs 8 lo=%GAMS.lo%';
jh = JobHandle;
put_utility fx 'log' / '>>> JobHandle :' jh;
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
option solvelink=%solveLink.chainScript%;
$include trnsport.gms
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
$if %system.filesys% == UNIX abort$(status <> 3) '*** Recollect after solve failed: wrong status';
$if not %system.filesys% == UNIX abort$(status <> 2) '*** Recollect after solve failed: wrong status';
$if not %system.filesys% == UNIX abort$errorlevel '*** Recollect after solve failed: wrong errorlevel';
$onEcho > SpawnJob.gms
$set flags mip=scip iterlim=30000 lo=2
file fx, fy /pid.inc/;
scalar jh,kill,status /1/;
Execute.ASync '=gams sleep --secs 3 lo=%GAMS.lo%';
jh = JobHandle;
put_utility fx 'log' / '>>> JobHandle :' jh;
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
putclose fy jh:0:0;
$offEcho
$call gams SpawnJob lo=%GAMS.lo%
$onEcho > CollectJob.gms
file fx;
scalar kill,status /1/;
scalar jh /
$include pid.inc
/;
put_utility fx 'log' / '>>> JobHandle :' jh;
while(status = 1,
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
display$sleep(1$(status=1)) 'sleep some';
);
$if %system.filesys% == UNIX abort$(status <> 3) '*** Collect Handle failed: wrong status';
$if not %system.filesys% == UNIX abort$(status <> 2) '*** Collect Handle failed: wrong status';
$if not %system.filesys% == UNIX abort$errorlevel '*** Collect Handle failed: wrong errorlevel';
$offEcho
$call gams CollectJob lo=%GAMS.lo%
$if errorlevel 1 $abort '*** Collect Handle failed'
$exit
*This needs some work to have something running on all platforms
Execute.ASync 'garbage dice %flags%';
jh = JobHandle;
put_utility fx 'log' / '>>> JobHandle :' jh;
status = JobStatus(jh);
put_utility fx 'log' / '>>> Status :' status;
abort$(Status<>0) '*** Should get an error when spawning garbage';