2010-04-07 29 views
5

Tôi có một hệ thống lấy mẫu. Tôi có nhiều chủ đề khách hàng trong ứng dụng quan tâm đến các Mẫu này, nhưng quá trình thực hiện lấy mẫu chỉ có thể xảy ra trong một ngữ cảnh. Đó là đủ nhanh mà nó okay cho nó để chặn quá trình gọi điện thoại cho đến khi lấy mẫu được thực hiện, nhưng đủ chậm mà tôi không muốn nhiều chủ đề chồng chất lên yêu cầu. Tôi đã đưa ra thiết kế này (tước xuống chi tiết tối thiểu):Đây có phải là thiết kế đồng bộ hóa chính xác không?

public class Sample 
{ 
    private static Sample _lastSample; 
    private static int _isSampling; 

    public static Sample TakeSample(AutomationManager automation) 
    { 
     //Only start sampling if not already sampling in some other context 
     if (Interlocked.CompareExchange(ref _isSampling, 0, 1) == 0) 
     { 
      try 
      { 
       Sample sample = new Sample(); 
       sample.PerformSampling(automation); 
       _lastSample = sample; 
      } 
      finally 
      { 
       //We're done sampling 
       _isSampling = 0; 
      } 
     } 

     return _lastSample; 
    } 

    private void PerformSampling(AutomationManager automation) 
    { 
     //Lots of stuff going on that shouldn't be run in more than one context at the same time 
    } 
} 

Điều này có an toàn để sử dụng trong trường hợp tôi mô tả không?

Trả lời

5

Có, có vẻ như an toàn vì int là một loại nguyên tử ở đây. Nhưng tôi vẫn sẽ tư vấn thay thế

private static int _isSampling; 

với

private static object _samplingLock = new object(); 

và sử dụng:

lock(_samplingLock) 
{ 
    Sample sample = new Sample(); 
    sample.PerformSampling(automation); 
    _lastSample = sample; 
} 

Đơn giản bởi vì nó là mô hình đề nghị và cũng đảm bảo tất cả các truy cập vào _lastSample được xử lý một cách chính xác.

NB: Tôi mong đợi tốc độ tương đương, khóa sử dụng lớp Monitor được quản lý sử dụng Interlocked nội bộ.

Edit:

tôi đã bỏ lỡ các khía cạnh back-off, đây là một phiên bản khác:

if (System.Threading.Monitor.TryEnter(_samplingLock)) 
    { 
    try 
    { 
     .... // sample stuff 
    } 
    finally 
    { 
      System.Threading.Monitor.Exit(_samplingLock); 
    } 
    } 
+0

+ 1 cho giải pháp đơn giản hơn. –

+1

Các TryEnter có lẽ là tốt hơn từ một quan điểm bảo trì, như nhiều khả năng nhiều người sẽ quen thuộc với Monitor.TryEnter hơn với Interlocked.CompareExchange. Tôi không quá lo lắng về chi phí trong trường hợp này, vì tôi chỉ lấy mẫu một vài lần mỗi giây. Khi nó thực sự thực hiện lấy mẫu, chi phí của quá trình lấy mẫu chính nó sẽ khá hơn một chút so với nguyên thủy khóa, tôi chắc chắn. –

+0

Tôi thích Monitor.TryEnter, nhưng chúng ta không nên sử dụng ReaderWriterLockSlim những ngày này ?? http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim_members.aspx –

-1

tôi thường tuyên bố một bool bay hơi và làm điều gì đó như:

private volatile bool _isBusy; 
private static Sample _lastSample; 

private Sample DoSomething() 
{ 
    lock(_lastSample) 
    { 
     if(_isBusy) 
      return _lastSample; 
     _isBusy = true; 
    } 

    try 
    { 
     _lastSample = new sameple//do something 
    } 
    finally 
    { 
     lock(_lastSample) 
     { 
      _isBusy = false; 
     } 
    } 
    return _lastSample; 
} 
+1

Nó không cần thiết để khai báo bool dễ bay hơi nếu bạn chỉ sử dụng nó bên trong một khóa anyway. Bên cạnh đó, đó là một thực tế rất xấu để khóa trên một lĩnh vực có thể thay đổi. Trong mẫu của bạn, có thể có hai khối khóa được nhập cùng một lúc. Khi bạn khóa trên một lĩnh vực có thể thay đổi, tôi sẽ mong đợi một bình luận chi tiết về lý do tại sao nó không thể làm tổn thương (nhiều) nếu hai (hoặc thậm chí nhiều hơn) đề nhập vào một khối khóa cùng một lúc. –

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