一、引言
Windows下的API接口函数CreateProcess()可以用来创建一个进程和主线程。新进程执行指定的可执行文件(一般为.exe文件)。但如果要创建的进程是一个GUI界面的启动程序(类似QQ启动界面),启动该进程需要加载插件,并且只有该进程的服务完全启动后,后续才能调用相应接口实现功能。此时如何准确的等待进程启动起来,即等待子进程启动时间的界定是个难题。
二、Windows MSDN 中CreateProcess的使用方法:
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPTSTR szCmdline=_tcsdup(TEXT("MyChildProcess"));
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
szCmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d)./n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
理论上讲,如果我创建的是Windows自带的程序如Nodepad.exe(记事本程序),此段代码首先通过CreateProcess()创建MyChildProcess=Nodepad.exe为子进程,子进程启动后父进程通过WaitForSingleObject()函数等待其执行的结束,在子进程没有退出前父进程是一直处于阻塞状态的,这里子进程的作用同单线程中的函数类似。一旦子进程退出,WaitForSingleObject()函数所等待的pi.hProcess对象将得到通知,父进程将得以继续,如有必要可以通过GetExitCodeProcess()来获取子进程的退出代码。
三、疑问点
但是,正如引言描述,如果是我们单独启动的进程需要花费一定的时间,比如10s才能启动起来。上面的WaitForSingleObject()的第二个参数如果仍为INFINITE无限等待的话是不妥当的,也就是说父进程是不知道创建的子进程花费多长时间启动起来的,死等并不能从根本上解决问题。
四、解决方案
在子进程的启动代码标志性部分(如启动起来标志,程序退出标志)加上退出写共享内存的代码,即将启动起来或中途退出用标记位标记写入共享内存。在创建子进程的下方轮询(间隔比如10ms一次)读取共享内存。
1)如果得到启动的标志位,则退出轮询继续执行;
2)如果得到中途退出的消息,则直接退出。这样就间接获取到了子进程的执行状态。
标记可以通过枚举类型设定,如下:
typedef enum _PROCESS_STATE_STATUS
{
PROCESS_STATE_OK, //正常启动;
PROCESS_STATE_TERMINIATE //中途退出;
} PROCESS_STATE_STATUS;
共享内存作为进程通信的方式之一,正好解决了父进程如何获取子进程执行状态的问题。
五、个人反思:
网络查询解决方案时,看到有人提出用:WaitForInputIdle解决。如下:调用进程可以通过WaitForInputIdle函数来等待新进程完成它的初始化并等待用户输入。这对于父进程和子进程之间的同步是极其有用的,因为CreateProcess函数不会等待新进程完成它的初始化工作。举例来说,在试图与新进程关联的窗口之前,进程应该先调用WaitForInputIdle。
但是:我也曾经代码实验,WaitForInputIdle这个函数在CreateProcess之后只是为新进程初始化进程代码然后就返回,并不是等进程完全创建好再返回。这一点大家可以用有界面的程序来测试,因为有界面的程序在代码初始化完成之后还要做一些其他事情然后再显示出界面的,所以创建有界面的程序显示界面的时候,WaitForInputIdle已经返回了。即:对于GUI界面的启动程序WaitForInputIdle是不起作用的。
作者:铭毅天下
转载请标明出处,原文地址:http://blog.csdn.net/laoyang360/article/details/18508131