2010-03-18 7 views
6

Tengo un recurso común, que quiero que 1 y solo 1 instancia de mi aplicación (o su API COM) tengan acceso en cualquier momento. He tratado de proteger este recurso utilizando mutexes, pero cuando varios hilos de una aplicación de punto de acceso de host intentan acceder al objeto COM, el mutex no parece ser liberado. Este es el código que he usado para proteger mi recurso.¿Cómo se protege un recurso común usando mutexes?

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

Si funciono los hilos simultáneamente, el primer hilo obtener de través (obviamente, siendo el primero para crear el mutex), pero las discusiones posteriores están atrapados en el bucle de repetición. Si ejecuto cada hilo a intervalos de 5 segundos, entonces todo está bien.

Sospecho que no estoy usando mutexes correctamente aquí, pero he encontrado muy poca documentación sobre cómo hacer esto.

¿Alguna idea?

Respuesta

14

Está utilizando el mutex incorrecto. Deberías estar esperándolo y soltándolo, no recreándolo constantemente.

Durante la inicialización:

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

Cuando se desea tener acceso al recurso

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

Durante la finalización

CloseHandle(Mutex); 

Además, dado que los mutex son globales, usted debe elegir algo un poco más único que "conexiones" para el nombre. Agregamos un GUID al final del nuestro.

+0

Debo agregar que esto solo funciona si configuro el segundo parámetro de CreateMutex en True. De lo contrario, tengo el mismo problema que antes con hilos colgados, cada uno esperándose el uno al otro. – Steve

+0

Impar La llamada WaitForSingleObject debe adquirir el mutex por usted. El ejemplo de MSDN también usa False: http://msdn.microsoft.com/en-us/library/ms686927%28VS.85%29.aspx –

+1

Craig tiene razón. Mi recomendación es * nunca * pasar 'True' para el segundo parámetro. La razón es que cuando la función vuelve, no tienes idea de si eres el propietario del mutex. Además, en el momento de la creación, probablemente no necesites el mutex de todos modos. Cree el mutex * una vez * cuando comience su programa. Luego adquiera y libere mientras se ejecuta su programa. Cuando finalice su programa, cierre el controlador. No cree ni destruya el mutex cada vez que necesite tenerlo. –

10

Pruebe con este sencillo código de demostración. Iniciar varias instancias de la aplicación, y se puede ver en el color de fondo cómo comparten el 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; 

Tenga en cuenta que he optado por utilizar la clase TMutex de la unidad SyncObjs, lo que simplifica las cosas.

+1

Esta es una buena respuesta también, pero Craig publicó primero y tiene menos representantes que usted. Ojalá pudiera aceptar ambas, ya que ambas son excelentes respuestas. – Steve

Cuestiones relacionadas