2011-08-16 25 views

Trả lời

17

Để giảm thiểu tác dụng phụ, đối tượng bị khóa không nên là đối tượng bị thao tác mà là một đối tượng riêng biệt được chỉ định khóa.

Tùy thuộc vào yêu cầu của bạn, có một vài lựa chọn để xử lý vấn đề này:

Variant A: Private đối tượng khóa

Chọn nút này nếu bạn chỉ muốn đảm bảo rằng DoSomething không xung đột với một thể hiện song song của DoSomething.

private static readonly object doSomethingLock = new object(); 

public static void DoSomething (string param1, string param2, SomeObject o) 
{ 
    //..... 

    lock(doSomethingLock) 
    { 
     o.Things.Add(param1); 
     o.Update(); 
     // etc.... 
    } 
} 

Biến thể B: Vượt qua khóa đối tượng như một tham số

Chọn này nếu truy cập vào o phải được thread-an toàn ngay cả bên ngoài DoSomething, ví dụ, nếu khả năng tồn tại mà người khác viết một phương pháp DoSomethingElse mà chạy song song với DoSomething và đó không phải can thiệp với khối lock trong DoSomething:

public static void DoSomething (string param1, string param2, SomeObject o, object someObjectLock) 
{ 
    //..... 

    lock(someObjectLock) 
    { 
     o.Things.Add(param1); 
     o.Update(); 
     // etc.... 
    } 
} 
.210

Variant C: Tạo thuộc tính

SyncRoot Nếu bạn có thể kiểm soát việc thực hiện các SomeObject, nó có thể là thuận tiện để cung cấp các đối tượng khóa như một tài sản. Bằng cách đó, bạn có thể thực hiện biến thể B mà không cần phải vượt qua xung quanh một tham số thứ hai:

class SomeObject 
{ 
    private readonly object syncRoot = new object(); 

    public object SyncRoot { get { return syncRoot; } } 

    ... 
} 

Sau đó, bạn chỉ cần sử dụng lock(o.SyncRoot) trong DoSomething. Đó là mô hình một số lớp BCL sử dụng, ví dụ: Array.SyncLock, ICollection.SyncRoot.

+2

Tôi tin rằng 'doSomethingLock' thường được gọi là' syncRoot'. – Sung

+0

Tôi nghĩ rằng tôi thấy tại sao bây giờ. Tôi không thể khóa tham chiếu được chuyển cho phương thức vì bất kỳ ai sử dụng đối tượng đó cũng sẽ có thể khóa nó. Trong thực tế, nó giống như làm khóa (điều này) nhưng đến một lớp khác. – ghostJago

+0

Các đối tượng khóa cũng phải là chỉ đọc. –

0

Dưới đây là một ví dụ về cách bạn nên sử dụng khóa:

class Account 
{ 
    decimal balance; 
    private Object thisLock = new Object(); 

    public void Withdraw(decimal amount) 
    { 
     lock (thisLock) 
     { 
      if (amount > balance) 
      { 
       throw new Exception("Insufficient funds"); 
      } 
      balance -= amount; 
     } 
    } 
} 

Và điều này có nghĩa rằng bạn khóa một Object đó là một biến riêng và chỉ được sử dụng cho khóa và không có gì khác,

Bạn wana có thể xem xét điều này:

lock Statement (C# Reference)

Thread Synchronization (C# and Visual Basic)

+0

Tôi đã xem ví dụ này từ nhiều nguồn khác nhau và tôi hiểu rằng những gì bạn đã nói là thực tiễn tốt nhất. Nhưng, cụ thể, những gì là sai với khóa toàn bộ đối tượng thats thông qua vào phương pháp? Sau khi tất cả, nó là một đối tượng quá. – ghostJago

+0

Nếu bạn thường xuyên khóa đối tượng được truyền vào, bạn tăng khả năng tạo bế tắc. https://en.wikipedia.org/wiki/Deadlock Về cơ bản, hai luồng đang chờ trên một khóa cho một đối tượng không bao giờ có thể được giải phóng. –

2

Chỉ cần trả lời câu hỏi thứ 3 của mình:

Hãy tưởng tượng rằng sau vào bạn quyết định khóa trên tham số phương pháp khác, có lẽ cái gì đó như:

public void XXX(object o) 
{ 
    lock(o) 
    { 

    } 
} 

Bạn sẽ có một thời gian khó khăn cố gắng để xem nếu có bế tắc. Bạn sẽ cần phải kiểm tra xem đối tượng có được truyền như tham số tới SomeObject o không bao giờ được truyền làm tham số cho đối tượng o cùng một lúc hay không.

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