2012-02-23 14 views
7

chciałbym wykonać proces potomny i zsynchronizować go (ewentualnie z Mutex) bez oczekiwania na proces potomny, aby zakończyć:Jak zsynchronizować wykonanie procesu rodzica/dziecka?

nadrzędny:

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. 

dziecka:

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. 

Spodziewam się wyświetlić dane wyjściowe:

Project1 : 1 
Project2 : 2 
Project1 : 3 

Problem polega na tym, że czasami rodzic (Project1.exe) nie opuszcza pętli.
Co robię źle?

Odpowiedz

11

Masz wyścig na muteksie. Mają nadzieję na następującej kolejności:

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

Ale to, co może się zdarzyć to

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

nie mogę całkiem zorientować, co twój ostateczny cel jest, ale mam podejrzenia, że ​​zdarzenie jest właściwie tym, czego szukasz.

W dominującej:

  1. Tworzenie nazwanego zdarzenia.
  2. Ustawienie zdarzenia na brak sygnału.
  3. Utwórz proces potomny.
  4. Poczekaj, aż wydarzenie zostanie zasygnalizowane.

u dziecka:

  1. Czy jakieś przetwarzanie.
  2. Otwórz nazwane wydarzenie.
  3. Ustawienie zdarzenia sygnalizowane, zwalniając w ten sposób rodzica z jego oczekiwania.

W bardzo wysokim poziomie kodu trzeba będzie wyglądać następująco:

nadrzędna

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

Dziecko

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

nie dołączyliśmy żadnego błędu kontrola. Jestem pewien, że możesz dodać trochę. Możesz również stwierdzić, że klasa opakowania zdarzeń w postaci SyncObjs jest wygodniejsza.


Wreszcie twój kod ma zajętą ​​pętlę. To prawie nigdy nie jest rozwiązaniem jakiegokolwiek problemu.Jeśli kiedykolwiek zauważysz, że piszesz zajętą ​​pętlę, powinieneś przyjąć to jako sygnał, że projekt jest nieprawidłowy. Chodzi o to, że w twoim kodzie, gdyby mógł on działać, proces macierzysty spaliłby 100% wykorzystania procesora podczas oczekiwania na proces potomny.

+0

10x, podejrzewałem, że mój projekt jest niepoprawny. Nie mogłem sobie uświadomić, jak używać 'WaitForSingleObject' w tym przypadku ... Czy mógłbyś mi pokazać, jak napisać poprawny kod do obsługi zdarzeń takich jak wyjaśniłeś? – ZigiZ

+0

OK, dodałem pseudokod. To jest bardzo łatwe. Wyraźnie wiesz, jak czytać dokumenty MSDN i jestem pewien, że możesz to samemu złamać. –

+0

Genialny! 10x! – ZigiZ

Powiązane problemy