2012-02-23 18 views
7

me gustaría ejecutar un proceso hijo y sincronizarlo (posiblemente con objeto mutex) sin esperar a que el proceso hijo:Cómo sincronizar la ejecución del proceso principal/secundario?

Padres:

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. 

Niño:

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. 

Espero ver una salida de:

Project1 : 1 
Project2 : 2 
Project1 : 3 

El problema es que a veces Parent (Project1.exe) no sale del ciclo.
¿Qué estoy haciendo mal?

Respuesta

11

Tienes una carrera en el mutex. Usted está esperando para la siguiente secuencia:

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

Pero lo que puede suceder es

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

yo no puedo trabajar en lo que su objetivo final es, pero tengo la sospecha de que un evento es en realidad lo que estás buscando.

En el padre:

  1. Crear un evento con nombre.
  2. Establezca el evento como no señalizado.
  3. Cree el proceso secundario.
  4. Espere hasta que se indique el evento.

En el niño:

  1. hacer algo de procesamiento.
  2. Abra el evento nombrado.
  3. Establezca el evento como señalizado, liberando al padre de su espera.

En muy alto nivel el código necesario se verá así:

Padres

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

Niño

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

yo no he incluido cualquier error comprobación. Estoy seguro de que puedes agregar algunos. También puede encontrar que la clase de contenedor de eventos en SyncObjs es más conveniente.


Finalmente, su código tiene un bucle ocupado. Eso casi nunca es la solución a ningún problema.Si alguna vez te encuentras escribiendo un ciclo ocupado, debes tomar eso como una señal de que el diseño es incorrecto. El punto es que, en su código, si se puede hacer que funcione, el proceso principal quemaría el 100% de utilización de CPU mientras espera el proceso secundario.

+0

10x, sospechaba que mi diseño es incorrecto. No pude darme cuenta de cómo usar 'WaitForSingleObject' en este caso ... ¿Puede mostrarme cómo escribir un código correcto para manejar eventos como los que explicó? – ZigiZ

+0

Bien, he agregado un pseudocódigo. Es muy fácil. Usted sabe claramente cómo leer los documentos de MSDN y estoy seguro de que puede descifrarlo usted mismo desde aquí. –

+0

¡Brillante! 10x! – ZigiZ

Cuestiones relacionadas