2010-03-18 7 views
6

Ho una risorsa comune, che voglio 1 e solo 1 istanza della mia applicazione (o la sua API COM) per avere accesso in qualsiasi momento. Ho provato a proteggere questa risorsa usando i mutex, ma quando più thread di un'applicazione host dotnet tentano di accedere all'oggetto COM, il mutex non sembra essere rilasciato. Questo è il codice che ho usato per proteggere la mia risorsa.Come si protegge una risorsa comune utilizzando mutex?

repeat 
    Mutex := CreateMutex(nil, True, PChar('Connections')); 
until (Mutex <> 0) and (GetLastError <> ERROR_ALREADY_EXISTS); 
    try 
    //use resource here! 
    finally 
    CloseHandle(Mutex); 
    end; 

Se corro i fili simultaneamente, il primo filo di ottenere attraverso (ovviamente, essendo il primo a creare il mutex), ma thread successivi vengono catturati nel ciclo di ripetizione. Se eseguo ogni thread a intervalli di 5 secondi, tutto va bene.

Ho il sospetto che non sto usando correttamente i mutex qui, ma ho trovato pochissima documentazione su come farlo.

Qualche idea?

risposta

14

Si sta usando il mutex sbagliato. Dovresti aspettarlo e rilasciarlo, non ricrearlo costantemente.

Durante l'inizializzazione:

Mutex := CreateMutex(nil, False, 'Connections'); 
if Mutex = 0 then 
    RaiseLastOSError; 

Quando si vuole accedere alla risorsa

if WaitForSingleObject(Mutex, INFINITE) <> WAIT_OBJECT_0 then 
    RaiseLastOSError; 
try 
    // Use resource here 
finally 
    ReleaseMutex(Mutex) 
end; 

Durante la finalizzazione

CloseHandle(Mutex); 

Inoltre, dal momento che mutex sono globali, si dovrebbe scegliere qualcosa di un po ' più unico di "connessioni" per il nome. Abbiamo aggiunto un GUID alla fine del nostro.

+0

Devo aggiungere che funziona solo se imposto il secondo parametro di CreateMutex su True. In caso contrario, ho lo stesso problema di prima con i thread appesi, ognuno in attesa l'uno dell'altro. – Steve

+0

Dispari. La chiamata WaitForSingleObject dovrebbe acquisire il mutex per te. L'esempio MSDN utilizza anche False: http://msdn.microsoft.com/en-us/library/ms686927%28VS.85%29.aspx –

+1

Craig ha ragione. La mia raccomandazione è di * mai * passare 'True' per il secondo parametro. Il motivo è che quando la funzione ritorna, non hai idea se possiedi effettivamente il mutex. Inoltre, al momento della creazione, probabilmente non è necessario possedere il mutex comunque. Crea il mutex * una volta * all'avvio del programma. Quindi acquisire e rilasciarlo mentre il programma viene eseguito. Quando il programma termina, chiudere la maniglia. Non creare e distruggere il mutex ogni volta che è necessario possederlo. –

10

Prova con questo semplice codice demo. Inizia varie istanze dell'applicazione, e si può vedere dal colore di sfondo come essi condividono il mutex:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    fMutex := SyncObjs.TMutex.Create(nil, False, 'GlobalUniqueName'); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    fMutex.Free; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    Color := clRed; 
    Update; 
    fMutex.Acquire; 
    try 
    Color := clGreen; 
    Update; 
    Sleep(5 * 1000); 
    finally 
    fMutex.Release; 
    end; 
    Color := clBtnFace; 
end; 

Nota che ho scelto di utilizzare la classe TMutex dall'unità SyncObjs, che semplifica le cose.

+1

Anche questa è una buona risposta, ma Craig ha postato per primo e ha meno rappresentanti di te. Vorrei poter accettare entrambe perché entrambe sono ottime risposte. – Steve

Problemi correlati