天天看點

解決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是不起作用的。

作者:銘毅天下

轉載請标明出處,原文位址:

http://blog.csdn.net/laoyang360/article/details/18508131

繼續閱讀