2012-02-23 39 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