2011-01-06 14 views
6

Chủ đề của tiện ích mở rộng này có an toàn không?Chủ đề của tiện ích mở rộng có an toàn không?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     if (handler != null) handler(sender, args); 
     } 
    } 

hoặc tôi có cần thay đổi không?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     var h = handler; 
     if (h!= null) h(sender, args); 
     } 
    } 
+0

chi tiết thiết kế và triển khai các sự kiện liên quan đến luồng http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

Trả lời

9

Bạn tìm thấy một lỗ vòng thú vị, nó đã đánh bại mọi người. Không, nó không an toàn.

Trong khi đó trông như EventHandler <> tham chiếu được sao chép thông qua đối số phương pháp, đây không phải là điều xảy ra khi chạy. Các phương thức mở rộng có thể được inlined, giống như một phương thức instance thông thường. Trong thực tế, nó là cực kỳ có khả năng nhận được nội tuyến vì nó quá nhỏ. Không có bản sao, bạn phải tự mình làm.

+1

Tôi không chắc chắn bạn là chính xác. Điều này sẽ chỉ áp dụng khi hàm gọi được gọi phương thức trên một giá trị mà có thể bị sửa đổi bởi một luồng khác (một trường lớp ví dụ thay vì một biến cục bộ). Tôi không biết liệu JIT có thể gọi một cuộc gọi như vậy trong trường hợp đó hay không. – tster

+0

Tuy nhiên, đây là một chủ đề rất thú vị. Tôi ước tôi không làm việc và có thời gian để đào sâu vào điều này. – tster

+1

Vâng, đó là những gì các thử nghiệm null trong mã nâng cao sự kiện là tất cả về. –

7

Cả hai phiên bản đều không an toàn, tùy thuộc vào ý bạn là "chủ đề an toàn". Xem xét phiên bản thứ hai của bạn:

var h = handler;   
    if (h!= null) 
     h(sender, args); 

"handler" là bản sao của một số trường có đại diện không thay đổi trong đó. Giả sử rằng trường đó bị biến đổi thành "null" trên một luồng khác sau khi kiểm tra null. Mã của bạn không bị lỗi trong trường hợp đó, bởi vì bạn đã tạo một bản sao của giá trị không null ban đầu. Nhưng chỉ đơn thuần là không bị lỗi không làm cho chương trình an toàn chủ đề an toàn. Một chương trình không sụp đổ nhưng vẫn tạo ra kết quả sai vẫn không phải là luồng an toàn.

Giả sử khi chủ đề khác đặt trường sự kiện thành rỗng, nó cũng làm biến đổi một số trạng thái mà nội dung trước đó cần để chạy chính xác. Bây giờ bạn sẽ chạy một trình xử lý sự kiện phụ thuộc vào trạng thái vừa bị đột biến trên một luồng khác; bạn đang chạy bộ xử lý sự kiện .

Không có cách nào dễ dàng để bảo vệ chống lại vấn đề này; nếu đó là tình huống bạn đang ở, thì bạn sẽ phải thiết kế logic luồng của bạn cực kỳ cẩn thận để đối phó với tình hình.

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