2010-09-10 32 views
14

thể trùng lặp:
Re-entrant locks in C#Recursive/khóa lồng nhau trong C# với tuyên bố khóa

Tôi đã nhìn ở đây trên StackOverflow và trên MSDN, và không thể tin rằng tôi couldn 't tìm thấy câu hỏi này kéo dài ra khỏi đó trên internets.

Giả sử tôi có một lớp học với một thành viên riêng tư mà tôi muốn truy cập trong một số phương pháp công khai. Các phương thức công khai này sẽ được gọi bởi các luồng khác nhau, do đó cần phải đồng bộ hóa.

public class MyClass 
{ 
    private Object SomeSharedData = new Object(); 

    public void MethodA() 
    { 
     lock(SomeSharedData) { 
      // do something 
      MethodB(); 
     } 
    } 

    public void MethodB() 
    { 
     lock(SomeSharedData) { 
      // do something 
     } 
    } 
} 

Lưu ý rằng MethodA và MethodB có thể được gọi bởi người dùng của lớp này, nhưng MethodA cũng gọi MethodB, dẫn đến tình trạng khóa lồng nhau.

Điều này có được đảm bảo an toàn không? Nói cách khác, không. NET xử lý này bằng cách tham chiếu đếm khóa, để khi tôi bật ra khỏi các phương pháp này, khóa bị giảm đi? Hoặc là. NET thực hiện một số phép thuật đằng sau hậu trường, theo đó nó chỉ đơn giản là bỏ qua tất cả các khóa tiếp theo trên đối tượng có nguồn gốc từ cùng một chủ đề?

+3

FYI khóa chỉ là cú pháp đường trên Monitor.Enter Monitor.Exit –

+0

@Sergey cảm ơn, tôi nghĩ rằng tôi thực sự đọc một lần trong cuốn sách C# của tôi nhưng không thể tìm thấy nó. – Dave

+0

@ M4N ack, tôi không kiểm tra "người tham gia lại" :) – Dave

Trả lời

16

Có, khóa dựa trên Monitor trong .NET là đệ quy và được tính.

Từ các tài liệu cho Monitor.Enter:

Đó là pháp lý cho các chủ đề tương tự để invoke Nhập nhiều hơn một lần mà không có nó chặn; tuy nhiên, số lượng bằng Cuộc gọi thoát phải được gọi trước các chủ đề khác đang chờ trên đối tượng sẽ bỏ chặn.

Cho dù đây là một điều tốt hay không được đề cử cho cuộc tranh luận ...

+0

Liên kết "lên tranh luận" được chuyển đến tài liệu Monitor.Enter. Bạn có thể chỉnh sửa câu trả lời của mình và cung cấp liên kết bạn dự định không? –

+0

ok, điều đó có ý nghĩa. Bây giờ tôi chỉ nên kiểm tra điều này với một ứng dụng nhỏ, nhưng tôi giả định rằng nếu một ngoại lệ được ném và không được xử lý trong câu lệnh lock() {}, thì số ref vẫn bị giảm đi? – Dave

+0

@Dave nó bị giảm. – eglasius

4

Vâng, Monitor hỗ trợ đệ quy, nhưng bạn nên lưu ý vì hành vi này khác với một đồng bộ hóa ban khác.

Ví dụ, ReaderWriterLockSlim theo mặc định không hỗ trợ đệ quy và đoạn mã này ném ngoại lệ:

public class MyClass 
{ 
    ReaderWriterLockSlim rw = new ReaderWriterLockSlim(); 
    //You should explicitly stated that you want to use recursion 
    ReaderWriterLockSlim rwWithRecursion = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion); 

    public void MethodA() 
    { 
     try { 
      rw.EnterReadLock(); 
      // do something 
      MethodB(); 
     } 
     finally { 
      rw.ExitReadLock(); 
     } 
    } 

    public void MethodB() 
    { 
     try { 
      rw.EnterReadLock(); //throws LockRecursionException 
     } 
     finally { 
      rw.ExitReadLock(); 
     } 
    } 
} 
+0

cảm ơn, tôi sẽ ghi nhớ điều đó. Tôi không tìm thấy nhu cầu cho ReaderWriterLockSlim được nêu ra, nhưng tôi đã đọc về nó trước và nó có thể có ích trong một ngày, vì vậy hy vọng tôi sẽ nhớ lời khuyên của bạn.:) – Dave

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