2012-02-23 6 views
7

Vorrei eseguire un processo figlio e sincronizzarlo (possibilmente con Mutex) senza attendere il processo figlio per terminare:Come sincronizzare l'esecuzione del processo padre/figlio?

principale:

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. 

bambini:

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. 

Mi aspetto di vedere un'uscita di:

Project1 : 1 
Project2 : 2 
Project1 : 3 

Il problema è che a volte il padre (Project1.exe) non sta uscendo dal ciclo.
Cosa sto sbagliando?

risposta

11

Hai una gara sul mutex. Si spera per la seguente sequenza:

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

Ma ciò che può accadere è

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

non riesco a capire che cosa il vostro obiettivo finale è, ma ho il sospetto che un evento è in realtà quello che stai cercando.

nel genitore:

  1. creare un evento di nome.
  2. Imposta l'evento su non segnalato.
  3. Creare il processo figlio.
  4. Attendere fino a quando non viene segnalato l'evento.

Nel bambino:

  1. fare alcune elaborazioni.
  2. Apre l'evento denominato.
  3. Imposta l'evento da segnalare, rilasciando quindi il genitore dall'attesa.

Nel livello molto alto il codice necessario sarà simile a questa:

Parent

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

Bambino

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

io non ho incluso alcun errore controllo. Sono sicuro che puoi aggiungerne un po '. È inoltre possibile che la classe wrapper evento in SyncObjs sia più comoda.


Infine, il codice ha un ciclo occupato. Non è quasi mai la soluzione a nessun problema.Se mai ti ritrovi a scrivere un ciclo occupato, dovresti prenderlo come segnale che il disegno non è corretto. Il punto è che, nel tuo codice, se poteva essere fatto funzionare, il processo genitore avrebbe bruciato il 100% di utilizzo della CPU mentre aspettava il processo figlio.

+0

10x, sospettavo che il mio disegno non fosse corretto. Non saprei come usare 'WaitForSingleObject' in questo caso ... Puoi per favore mostrarmi come scrivere un codice corretto per gestire eventi come hai spiegato? – ZigiZ

+0

OK, ho aggiunto qualche pseudo-codice. È molto facile. Sai chiaramente come leggere i documenti MSDN e sono sicuro che puoi craccarlo da qui. –

+0

Brillante! 10x! – ZigiZ