解决CreateProcess()的等待时间问题

简介: 一、引言: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是不起作用的。


相关文章
|
1月前
【进程控制】超详细讲解wait和waitpid的原理(结合代码)
【进程控制】超详细讲解wait和waitpid的原理(结合代码)
|
7月前
|
程序员 Linux Shell
【CSAPP】进程控制 | 系统调用错误处理 | 进程状态 | 终止进程 | 进程创建 | 回收子进程 | 与子进程同步(wait/waitpid) | execve 接口
【CSAPP】进程控制 | 系统调用错误处理 | 进程状态 | 终止进程 | 进程创建 | 回收子进程 | 与子进程同步(wait/waitpid) | execve 接口
66 0
|
Shell Linux C语言
【Linux进程】六、wait()函数——子进程回收
【Linux进程】六、wait()函数——子进程回收
410 0
【Linux进程】六、wait()函数——子进程回收
|
Linux
wait() 函数和 waitpid() 函数
wait() 函数和 waitpid() 函数
629 0
wait() 函数和 waitpid() 函数
|
物联网 Linux 开发者
线程 pthread_exit 时执行清理程序|学习笔记
快速学习线程 pthread_exit 时执行清理程序
144 0
线程 pthread_exit 时执行清理程序|学习笔记
|
监控 安全 Java
关闭线程的正确方法:“优雅”的中断
前文从任务到线程:Java结构化并发应用程序中介绍了如何安排任务启动线程。 线程在启动之后,正常的情况下会运行到任务完成,但是有的情况下会需要提前结束任务,如用户取消操作等。
1361 0
|
Java Linux Android开发
关于Signal Catcher线程中对线程的理解
关于Signal Catcher线程中对线程的理解
142 0
|
Java API
如何优雅地终止一个线程?
我们的系统肯定有些线程为了保证业务需要是要常驻后台的,一般它们不会自己终止,需要我们通过手动来终止它们。我们知道启动一个线程是start方法,自然有一个对应的终止线程的stop方法,通过stop方法可以很快速、方便地终止一个线程,我们来看看stop的源代码。
135 0
如何优雅地终止一个线程?
|
编解码
QProcess调用ffprobe.exe获取视频总时间
ffprobe.exe是ffmpeg自带可执行程序,ffmpeg是很强大的多媒体框架,包含了解码、编码、转码、解码、混合、流媒体等等众多功能。
487 0
创建线程后为什么关闭了线程句柄,线程还是可以运行?
主线程只要拥有线程句柄,事后就可以对线程执行某些操作,比如查询线程状态等等,靠的就是句柄,如果没有句柄,系统就无从知道要查的是那个线程的状态。但保持这个句柄不关闭,并不是线程运行的条件。
287 0