【问题标题】:How to synchronize Parent/Child process execution?如何同步父/子进程执行?
【发布时间】:2012-02-23 14:12:42
【问题描述】:

我想执行一个子进程并同步它(可能与 Mutex),而不等待子进程终止:

家长:

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

问题是有时父 (Project1.exe) 没有退出循环。
我做错了什么?

【问题讨论】:

    标签: delphi winapi delphi-7


    【解决方案1】:

    您在互斥体上存在竞争。您希望以下顺序:

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

    但可能发生的是

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

    我无法确定您的最终目标是什么,但我怀疑某个事件实际上是您正在寻找的。​​p>

    在父级中:

    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 利用率。

    【讨论】:

    • 10x,我怀疑我的设计不正确。我不知道在这种情况下如何使用WaitForSingleObject...你能告诉我如何编写正确的代码来处理你解释的事件吗?
    • 好的,我添加了一些伪代码。这很容易。您清楚地知道如何阅读 MSDN 文档,我相信您可以从这里自行破解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 2019-06-17
    • 1970-01-01
    • 2021-09-13
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多