2011-11-26 20 views
8

Tôi mất mã DCL từ Joe Duffy của cuốn sách 'lập trình đồng thời trên cửa sổ'Những loại hoạt động 'bay hơi' là cần thiết trong hai lần kiểm tra khóa trong .NET

class LazyInit<T> where T : class 
{ 
private volatile T m_value; 
private object m_sync = new object(); 
private Func<T> m_factory; 
public LazyInit(Func<T> factory) { m_factory = factory; } 
public T value 
{ 
    get 
    { 
    if (m_value == null) 
    { 
     lock (m_sync) 
     { 
     if (m_value == null) 
     { 
      m_value = m_factory(); 
     } 
     } 
    } 
    return m_value; 
    } 
} 
} 

người ta nói đánh dấu m_value dễ bay hơi có thể ngăn chặn viết sắp xếp lại sẽ dẫn đến các chủ đề khác nhận được 'đối tượng không null với các trường chưa được khởi tạo'. Nếu vấn đề xảy ra chỉ bởi vì có thể viết sắp xếp lại, tôi có thể chỉ sử dụng 'Viết dễ bay hơi' thay vì đánh dấu các biến dễ bay hơi, như dưới đây? (Mã này trông một chút lúng túng cho cuộc biểu tình, tôi chỉ muốn chắc chắn nếu chúng ta chỉ có thể sử dụng ghi ổn định thay vì)

class LazyInit<T> where T : class 
{ 
private object m_value; 
private object m_sync = new object(); 
private Func<T> m_factory; 
public LazyInit(Func<T> factory) { m_factory = factory; } 
public T value 
{ 
    get 
    { 
    if (m_value == null) 
    { 
     lock (m_sync) 
     { 
     if (m_value == null) 
     { 
      Thread.VolatileWrite(ref m_value, m_factory()); 
     } 
     } 
    } 
    return (T)m_value; 
    } 
} 
} 

Một câu hỏi có liên quan là phiên bản đan cài từ cuốn sách

class LazylnitRelaxedRef<T> where T : class 
{ 
private volatile T m_value; 
private Func<T> m_factory; 
public LazylnitRelaxedRef(Func<T> factory) { m_factory = factory; } 
public T Value 
{ 
    get 
    { 
    if (m_value == null) 
     Interlocked.CompareExchange(ref m_value, m_factory(), null); 
    return m_value; 
    } 
} 
} 

Kể từ thông số kỹ thuật ECMA-CLI 'Thao tác liên khóa thực hiện các hoạt động thu nhận/giải phóng tiềm ẩn', chúng ta vẫn cần biến động trong trường hợp này?

+2

Có sự khác biệt quan trọng giữa mô hình bộ nhớ ECMA và mô hình bộ nhớ .net 2. – CodesInChaos

+0

Tại sao bạn cần thực hiện khóa kiểm tra kép? Bạn có quan sát thấy vấn đề hiệu suất với ứng dụng của mình bằng cách lấy khóa không? –

+1

@CodeInChaos, hãy giải thích về "điểm khác biệt quan trọng" là gì. – Amy

Trả lời

1

Đầu tiên, gây rối với biến động là thực sự khó khăn, vì vậy đừng quá lỏng lẻo với nó! Nhưng, here là câu trả lời thực sự gần với câu hỏi của bạn và here là một bài viết mà tôi nghĩ mọi người nên đọc trước khi sử dụng từ khóa volatile và chắc chắn trước khi bắt đầu sử dụng VolatileRead, VolatileWriteMemoryBarrier.

Câu trả lời trong liên kết đầu tiên là: bạn không cần sử dụng dễ bay hơi, bạn chỉ cần sử dụng System.Threading.Thread.MemoryBarrier() QUYỀN TRƯỚC KHI bạn chỉ định giá trị mới. Điều này là do các release_fence ngụ ý khi sử dụng từ khóa dễ bay hơi đảm bảo rằng nó được hoàn thành bằng văn bản ra bộ nhớ chính, và rằng không có hoạt động đọc/ghi có thể được thực hiện cho đến khi nó kết thúc.

Vì vậy, Thread.VolatileWrite() làm gì và thực hiện các chức năng tương tự mà chúng tôi nhận được từ từ khóa 'dễ bay hơi'? Vâng, đây là mã đầy đủ của hàm này:

public static void VolatileWrite (ref int address, int value) 
{ 
    MemoryBarrier(); address = value; 
} 

Có, nó gọi MemoryBarrier ngay trước khi nó gán giá trị của bạn, là đủ!

+0

, Xin lỗi vì đã đánh lừa bạn bởi mã, tôi đã được yêu cầu, cho DCL, có bất kỳ vấn đề trong một số mô hình bộ nhớ yếu hơn nếu đọc là không dễ bay hơi hoặc không áp dụng mua hàng rào đọc? BTW, .net sử dụng hàng rào đầy đủ để thực hiện API Thread.VolatileRead và Thread.VolatileWrite, có nghĩa là chúng mạnh hơn đọc dễ bay hơi và ghi dễ bay hơi. Đối với câu hỏi của tôi, chúng ta hãy xem xét các trường hợp đọc dễ bay hơi, không phải là một API. (Một lần nữa, xin lỗi vì gây hiểu nhầm bạn bởi mã) – Fei

+1

Hành vi dễ bay hơi ban đầu là đặt một rào cản trước khi viết và sau khi đọc. Tôi muốn đề xuất một rào cản bộ nhớ trước và sau khi các hoạt động viết và trước khi một hoạt động đọc. Nếu chúng ta viết và sau đó đọc ngay lập tức sau đó, chúng tôi có nguy cơ rằng 2 hoạt động này được hoán đổi vì không có rào cản giữa chúng. –

+0

@Ivaylo Slavov, cho 'đổi chỗ', bạn có thể cho tôi biết thêm thông tin về những gì sẽ xảy ra trong trường hợp này để phá vỡ DCL không? BTW, liệu 'trao đổi' này có phá vỡ sự phụ thuộc dữ liệu không? – Fei

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