2012-02-23 63 views
7

我想執行一個子進程(可能與互斥)進行同步,而無需等待子進程終止:如何同步父/子流程執行?

家長:

program Project1; 
{$APPTYPE CONSOLE} 
uses 
    Windows, ShellApi, SysUtils, Dialogs; 

procedure ShellExecEx(Wnd: HWND; const AExeFilename, AParams: string); 
const 
    SEE_MASK_NOZONECHECKS = $00800000; 
    SEE_MASK_WAITFORINPUTIDLE = $02000000; 
    SEE_MASK_NOASYNC = $00000100; 
var 
    Info: TShellExecuteInfo; 
begin 
    FillChar(Info, SizeOf(Info), 0); 
    Info.Wnd := Wnd; 
    Info.cbSize := SizeOf(Info); 
    Info.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOZONECHECKS or 
    SEE_MASK_NOASYNC 
    //or SEE_MASK_WAITFORINPUTIDLE (works only with UI app ???) 
    //or SEE_MASK_NO_CONSOLE 
    //or SEE_MASK_NOCLOSEPROCESS 
    ; 
    Info.lpVerb := ''; 
    Info.lpFile := PChar(AExeFilename); 
    Info.lpParameters := PChar(AParams); 
    Info.lpDirectory := PChar(ExtractFilePath(AExeFilename)); 
    Info.nShow := SW_SHOWNORMAL; 
    if not ShellExecuteEx(@Info) then 
    RaiseLastOSError; 
    CloseHandle(Info.hProcess); 
end; 

var 
    Mutex: THandle = 0; 
    Error: DWORD; 
begin 
    OutputDebugString('Project1 : 1'); 

    ShellExecEx(0, 'Project2.exe', ''); 

    // synchronize 
    repeat 
    // attempt to create a named mutex 
    Mutex := CreateMutex(nil, False, 'F141518A-E6E4-4BC0-86EB-828B1BC48DD1'); 
    Error := GetLastError; 
    if Mutex = 0 then RaiseLastOSError; 
    CloseHandle(Mutex); 
    until Error = ERROR_ALREADY_EXISTS; 

    OutputDebugString('Project1 : 3'); 
end. 

兒童:

program Project2; 
{$APPTYPE CONSOLE} 
uses 
    SysUtils, Windows, Dialogs; 

var 
    Mutex: THandle = 0; 
begin 
    OutputDebugString('Project2 : 2'); 
    // attempt to create a named mutex and acquire ownership 
    Mutex := CreateMutex(nil, True, 'F141518A-E6E4-4BC0-86EB-828B1BC48DD1'); 
    if Mutex = 0 then RaiseLastOSError; 

    // do something 

    ReleaseMutex(Mutex); 
    CloseHandle(Mutex); // <- at this point Program1.exe should exit the repeat loop 

    ShowMessage('ok from Project2'); 
end. 

我期待看到輸出:

Project1 : 1 
Project2 : 2 
Project1 : 3 

問題是,有時Parent(Project1.exe)不退出循環。
我在做什麼錯?

回答

11

你有互斥競賽。您希望以下順序:

child: create mutex 
parent: open mutex 
child: destroy mutex 

但會發生什麼是

child: create mutex 
child: destroy mutex 
parent: open mutex (fails because mutex is destroyed) 

我不能完全制定出你的最終目標是什麼,但我有一個懷疑,一個事件實際上你在找什麼。

在父:

  1. 創建一個名爲事件。
  2. 將事件設置爲無信號。
  3. 創建子進程。
  4. 等到事件發出信號。

在孩子:

  1. 做一些處理。
  2. 打開指定事件。
  3. 將事件設置爲發送信號,從而釋放父母的等待。

在非常高的水平,你需要看起來像這樣的代碼:

家長

Event = CreateEvent(nil, True, False, EventName); 
//create it manual reset, set to non-signaled 
ShellExecEx(....); 
WaitForSingleObject(Event); 

兒童

Event = CreateEvent(nil, True, False, EventName); 
//do stuff 
SetEvent(Event); 

我不包含任何錯誤檢查。我相信你可以添加一些。您還可能會發現SyncObjs中的事件包裝類更方便。


最後,你的代碼有一個繁忙的循環。這幾乎從來不是解決任何問題的方法。如果您發現自己正在編寫一個繁忙的循環,則應該將其作爲設計不正確的信號。問題的關鍵在於,在你的代碼中,如果它能夠工作,父進程會在等待子進程的同時消耗100%的CPU利用率。

+0

10倍,我懷疑我的設計是不正確的。我無法理解如何在這種情況下使用'WaitForSingleObject' ...你能告訴我如何編寫一個正確的代碼來處理像你所解釋的事件嗎? – ZigiZ 2012-02-23 15:05:35

+0

好的,我添加了一些僞代碼。這很容易。你清楚知道如何閱讀MSDN文檔,我相信你可以從這裏自己破解它。 – 2012-02-23 15:11:06

+0

太棒了! 10倍! – ZigiZ 2012-02-23 15:39:16