2010-03-18 21 views
6

Tôi có một tài nguyên chung, mà tôi muốn 1 và chỉ 1 phiên bản của ứng dụng của tôi (hoặc đó là COM API) để có quyền truy cập vào bất kỳ lúc nào. Tôi đã cố gắng để bảo vệ tài nguyên này bằng cách sử dụng mutexes, nhưng khi nhiều chủ đề của một ứng dụng máy chủ lưu trữ dotnet cố gắng truy cập vào đối tượng COM, mutex dường như không được phát hành. Đây là mã tôi đã sử dụng để bảo vệ tài nguyên của mình.Làm cách nào để bảo vệ tài nguyên chung bằng mutexes?

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

Nếu tôi chạy đồng thời, chuỗi đầu tiên nhận được thông qua (rõ ràng là chuỗi đầu tiên tạo ra mutex), nhưng các chuỗi tiếp theo sẽ bị lặp lại. Nếu tôi chạy mỗi thread ở khoảng thời gian 5 giây, thì tất cả đều ổn.

Tôi nghi ngờ tôi không sử dụng mutexes chính xác ở đây, nhưng tôi đã tìm thấy rất ít tài liệu về cách thực hiện việc này.

Bất kỳ ý tưởng nào?

Trả lời

14

Bạn đang sử dụng mutex sai. Bạn nên chờ đợi nó và phát hành nó, không tái tạo nó liên tục.

Trong thời gian khởi:

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

Khi bạn muốn truy cập vào tài nguyên

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

Trong quyết toán

CloseHandle(Mutex); 

Ngoài ra, vì mutexes là toàn cầu, bạn nên chọn một cái gì đó một chút độc đáo hơn "kết nối" cho tên. Chúng tôi đã thêm GUID vào cuối của chúng tôi.

+0

Tôi nên thêm rằng điều này chỉ hoạt động nếu tôi đặt tham số thứ hai của CreateMutex thành True. Nếu không, tôi nhận được cùng một vấn đề như trước với chủ đề treo, mỗi chủ đề chờ đợi nhau. – Steve

+0

Odd. Cuộc gọi WaitForSingleObject sẽ có được mutex cho bạn. Ví dụ MSDN cũng sử dụng False: http://msdn.microsoft.com/en-us/library/ms686927%28VS.85%29.aspx –

+1

Craig đúng. Khuyến nghị của tôi là * không bao giờ * chuyển 'True' cho tham số thứ hai. Lý do là khi hàm trả về, bạn không biết liệu bạn có thực sự sở hữu mutex hay không. Hơn nữa, vào thời điểm sáng tạo, có thể bạn không cần phải sở hữu mutex. Tạo mutex * một lần * khi chương trình của bạn bắt đầu. Sau đó, có được và phát hành nó khi chương trình của bạn chạy. Khi chương trình của bạn chấm dứt, hãy đóng chốt xử lý. Không tạo và phá hủy mutex mỗi khi bạn cần sở hữu nó. –

10

Hãy thử với mã trình diễn đơn giản này. Bắt đầu một số trường hợp của ứng dụng, và bạn có thể nhìn thấy từ màu nền cách họ chia sẻ các 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; 

Lưu ý rằng tôi đã chọn để sử dụng lớp TMutex từ các đơn vị SyncObjs, mà đơn giản hóa mọi thứ.

+1

Đây cũng là một câu trả lời hay, nhưng Craig đã đăng đầu tiên và anh ấy có ít đại diện hơn bạn. Tôi ước tôi có thể chấp nhận cả hai vì cả hai đều là những câu trả lời tuyệt vời. – Steve

Các vấn đề liên quan