2010-03-19 33 views
5

Tôi đã đọc câu trả lời cho một similar question, nhưng tôi vẫn còn một chút nhầm lẫn ... Abel đã có một câu trả lời tuyệt vời, nhưng đây là phần mà tôi không chắc chắn về:Liệu khả năng hiển thị đảm bảo được khóa liên động với các chủ đề khác trong C# hay tôi vẫn phải sử dụng dễ bay hơi?

.. .declaring biến biến động làm cho nó dễ bay hơi cho mỗi truy cập duy nhất. Không thể ép buộc hành vi này theo bất kỳ cách nào khác, do đó dễ bay hơi không thể được thay thế bằng Lồng vào nhau. Điều này là cần thiết trong các trường hợp trong đó các thư viện, giao diện khác hoặc phần cứng có thể truy cập biến của bạn và cập nhật bất cứ lúc nào hoặc cần phiên bản gần đây nhất .

Liệu Interlocked tầm nhìn bảo đảm các hoạt động nguyên tử cho tất cả các chủ đề, hay tôi vẫn phải sử dụng từ khóa volatile trên giá trị để đảm bảo tầm nhìn của sự thay đổi?

Dưới đây là ví dụ của tôi:

volatile int value = 100000; // <-- do I need the volitile keyword 
// .... 

public void AnotherThreadMethod() 
{ 
while(Interlocked.Decrement(ref value)>0) 
{ 
    // do something 
} 
} 


public void AThreadMethod() 
{ 
while(value > 0) 
{ 
    // do something 
} 
} 

Cập nhật:
tôi còn là một môn thể thao xấu và tôi đã thay đổi ví dụ ban đầu, do đó, đây là một lần nữa:

public class CountDownLatch 
{ 
    private volatile int m_remain; // <--- do I need the volatile keyword here? 
    private EventWaitHandle m_event; 

    public CountDownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 
+0

Xin lỗi vì đã có nhiều chỉnh sửa ... Remus là một môn thể thao tốt về nó. Cảm ơn vì thông tin! :) – Kiril

Trả lời

5

Them không * cần ** biến động, bởi vì bạn không bao giờ kiểm tra giá trị của biến liên khóa. Thay vào đó, bạn luôn kiểm tra giá trị trả lại bằng (các) hoạt động liên khóa. Trộn các hoạt động liên khóa và việc gán/so sánh thông thường luôn dẫn đến mã không chính xác.

Tôi không chắc ý định của hàm Reset() là gì, nhưng đoạn mã đó không có vị trí trong nguyên thủy chủ đề: bạn gán cho m_remain, bạn kiểm tra giá trị của m_remain trực tiếp, là khá xấu. Tôi mạnh mẽ đề nghị bạn lấy nó ra: không chỉ được thực hiện không chính xác, nhưng tôi rất nghi ngờ ngữ nghĩa của 'đặt lại' truy cập giữa tuổi thọ là cần thiết. Để nó đơn giản: ctor (di chuyển mã từ Đặt lại vào nó) Tín hiệu và Chờ đợi là ba toán tử duy nhất cần thiết, và chúng chính xác như bây giờ.

Cập nhật Sau khi bạn chỉnh sửa mã.

Bỏ qua thực tế là bạn không nên kết hợp cả hai, nếu bạn kết thúc việc trộn chúng thì có, vẫn dễ bay hơi. Dễ bay hơi chủ yếu về mã IL và mã JIT được tạo để đảm bảo giá trị luôn được đọc từ vị trí bộ nhớ thực tế và không có tối ưu hóa xảy ra, như sắp xếp lại mã. Thực tế là một đoạn mã không liên quan cập nhật giá trị bằng cách sử dụng các hoạt động được khóa liên động không ảnh hưởng đến các phần khác đọc giá trị. W/o thuộc tính volatile, trình biên dịch/JIT vẫn có thể tạo mã bỏ qua các ghi xảy ra ở một nơi khác, không liên quan nếu viết được khóa liên động hoặc gán trực tiếp.

BTW, có các mẫu hợp lệ kết hợp các hoạt động đọc và lồng vào nhau thông thường, nhưng chúng thường liên quan đến Interlocked.CompareExchange và như sau: đọc trạng thái hiện tại, thực hiện một số tính toán dựa trên trạng thái hiện tại. so sánh trao đổi: nếu thành công tốt, nếu không làm giảm kết quả tính toán và quay lại bước 1.

+0

Vâng, bài đăng của tôi có ý nghĩa trước khi chỉnh sửa của bạn lol –

+0

Xin lỗi, tôi đã sao lưu ví dụ ... Tôi thực sự không có ý định lừa bạn! :) – Kiril

+0

Vì vậy, ra đi chức năng Đặt lại ... nó thực sự đã không làm cho bất kỳ ý nghĩa. Tôi nghĩ rằng nó có thể hữu ích cho việc tái sử dụng cùng một chốt, nhưng nó thêm nhiều sự nhầm lẫn hơn bất cứ điều gì khác. – Kiril

1

Tôi nghĩ System.Threading.Thread.VolatileRead (ref myVariable) có thể là những gì bạn đang tìm kiếm.Sử dụng kết hợp với Interlocked.Increment nó có thể được sử dụng để đảm bảo rằng những thay đổi là nguyên tử và các giá trị mà bạn đọc là mới nhất.