Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Starting an external process asynchronously

Dominik_H_
Beginner
330 Views

Hello,

in my Fortran program, I want to start an external process and directly return to my program, not waiting for its completion. 
Thus, as I understand it, the compiler routines RUNQQ, SYSTEM or SYSTEMQQ are not suitable for this problem.

I have read about the possibility to use the Windows-Routine CreateProcess instead and implemented the following function:

subroutine start_help()
c-----------------------------------------------------------------------
c
c.... Purpose: start an external process
c-----------------------------------------------------------------------
use Kernel32
implicit none
INTEGER(BOOL) :: res, bIH
INTEGER(DWORD) :: dCF
INTEGER(LPVOID) :: lpE
CHARACTER(len=500) :: fcis, fcis1
TYPE( T_SECURITY_ATTRIBUTES ) tPA, tTA
TYPE( T_PROCESS_INFORMATION ) tPI
TYPE( T_STARTUPINFO ) tSI
 bIH = FALSE ! inherit handles [bool] dCF = NULL ! creation flags [dword]
lpE = NULL ! environment [lpStr]

fcis = "C:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\
+AcroRd32.exe"C
fcis1 = "/s /o C:\\path\\to\\my.pdf"C
res = CreateProcess(fcis,fcis1,tPA,tTA,bIH,dCF,lPE,NULL,tSI,tPI) if (res .eq. 0) then
write(16,*) "Error! Could not create process.",GetLastError()
end if
return
end

This routine works fine when calling it in a blank test program, which does nothing but call this routine.

However, as soon as I implement it to my larger program, it somehow refuses to work at all.
I tried adding a break point to the subroutine, but somehow the debugger just skips the whole routine, even when setting the break point to its call-statement and proceding with single steps.

The routine is called though, as test and error output is written just fine.

CreateProcess seems to fail too, as there is no process opened, even with other executables. The GetLastError error code is 0.

I am using Visual Studio 2010 with Intel(R) Visual Fortran Compiler XE 13.0.0.089 [Intel(R) 64]. I have used the same compiler for both programs.
No external libraries are used, OpenMP is activated but the routine and its calls are outside of parallel regions. 

Thanks for your help!

0 Kudos
3 Replies
IanH
Honored Contributor II
330 Views
Some of the arguments (the derived type ones) passed to CreateProcess don't look like they are being initialised. The values of those arguments will be random garbage in a larger program which may cause odd things to happen (in a smaller program their values may be somewhat consistent, to the extent that things seem to work, but there be dragons near). Most of those arguments you don't need to supply anything other than a NULL pointer for, unless you are doing fancy stuff. This snippet doesn't do what you want - it explicitly waits for the process to terminate - but should give you an idea of how to use CreateProcess. If you obliterate the wait_result, bool_result and success_flag assignment statements towards the end of the procedure (leave the cleanup bit!) then things should carry on asynchronously. It is an internal procedure in a main program - while I don't see any host associated stuff in this section of code there may be the odd declaration missing. [fortran] !***************************************************************************** !! !> Execute a child program, determine whether it succeeded or failed based !! on the process exit code. !! !! @param[in] command_name The name of the executable file for the !! program to execute. !! !! @param[in] command_line The command line to execute. Typically !! the first argument would be the same as @a command_name. !! !! @param[out] success_flag Flag to indicate whether successful !! termination of the command was detected. This is based on the process !! exit code being zero. SUBROUTINE check_return_code(command_name, command_line, success_flag) USE IFWIN !--------------------------------------------------------------------------- ! Arguments CHARACTER(*), INTENT(IN) :: command_name CHARACTER(*), INTENT(IN) :: command_line LOGICAL, INTENT(OUT) :: success_flag !--------------------------------------------------------------------------- ! Local variables INTEGER(BOOL) :: bool_result TYPE(T_STARTUPINFO) :: startup_info TYPE(T_PROCESS_INFORMATION) :: proc_info INTEGER(DWORD) :: wait_result INTEGER(DWORD) :: process_code !*************************************************************************** CALL ZeroMemory(LOC(startup_info), SIZEOF(startup_info)) startup_info%cb = SIZEOF(startup_info) bool_result = CreateProcess( & command_name // ACHAR(0), & ! LPCTSTR lpApplicationName command_line // ACHAR(0), & ! LPTSTR lpCommandLine 0, & ! LPSECURITY_ATTRIBUTES lpProcessAttributes 0, & ! LPSECURITY_ATTRIBUTES lpThreadAttributes 1_BOOL, & ! BOOL bInheritHandles 0_DWORD, & ! DWORD dwCreationFlags 0, & ! LPVOID lpEnvironment 0, & ! LPCTSTR lpCurrentDirectory startup_info, & ! LPSTARTUPINFO lpStartupInfo, proc_info ) ! LPPROCESS_INFORMATION lpProcessInformation wait_result = WaitForSingleObject(proc_info%hProcess, INFINITE) bool_result = GetExitCodeProcess(proc_info%hProcess, LOC(process_code)) success_flag = process_code == 0 ! Cleanup. bool_result = CloseHandle(proc_info%hProcess) bool_result = CloseHandle(proc_info%hThread) END SUBROUTINE check_return_code [/fortran] Note that I don't go in for this 'string'C business - I prefer to stick with the standard fortran approach to creating a null terminated string. (Edit to further note that I don't have some sort of bizarre vertical spacing convention - that's just the forum software botching things.)
0 Kudos
Dominik_H_
Beginner
330 Views
Thanks, that was exactly the problem. :) Works just fine now.
0 Kudos
TimP
Honored Contributor III
330 Views
Until Execute_Command_Line appears in ifort, could you use one of those ifort system functions to start a background process? The start command of cmd shell, or the usual background "&" of bash and similar shells, might perform your task.
0 Kudos
Reply