我想执行子进程并同步它(可能与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)没有退出循环.
我究竟做错了什么?
解决方法
你在互斥锁上有一场比赛.您希望以下顺序:
child: create mutex parent: open mutex child: destroy mutex
但可能发生的是
child: create mutex child: destroy mutex parent: open mutex (fails because mutex is destroyed)
我无法确定你的最终目标是什么,但我怀疑事件实际上是你在寻找什么.
在父母:
>创建命名事件.
>将事件设置为无信号.
>创建子进程.
>等到事件发出信号.
在孩子:
>做一些处理.
>打开命名事件.
>将事件设置为发信号,从而从父级等待中释放父级.
在非常高的级别,您需要的代码将如下所示:
亲
Event = CreateEvent(nil,EventName); //create it manual reset,set to non-signaled ShellExecEx(....); WaitForSingleObject(Event);
儿童
Event = CreateEvent(nil,EventName); //do stuff SetEvent(Event);
我没有包含任何错误检查.我相信你可以添加一些.您可能还会发现SyncObjs中的事件包装器类更方便.
最后,您的代码有一个繁忙的循环.这几乎不是任何问题的解决方案.如果您发现自己编写了一个繁忙的循环,那么您应该将其视为设计不正确的信号.关键是,在您的代码中,如果可以使其工作,父进程将在等待子进程时消耗100%的cpu利用率.