2017-05-20 27 views
5

Việc thực hiện Volatile.Read chỉ chèn một rào cản bộ nhớ sau khi đọc:Tại sao Volatile.Read lấy tham số ref?

public static int Read(ref int location) 
{ 
    var value = location; 
    Thread.MemoryBarrier(); 
    return value; 
} 

Do đó, việc sử dụng các phương pháp như vậy ...

return Volatile.Read(ref _a) + Volatile.Read(ref _b); 

... sẽ tương đương với:

var a = _a; 
Thread.MemoryBarrier(); 
var b = _b; 
Thread.MemoryBarrier(); 
return a + b; 

Cho ở trên, hành vi kết quả sẽ không giống nhau nếu tham số không phải là ref?

public static int Read(int value) 
{ 
    Thread.MemoryBarrier(); 
    return value; 
} 

Tôi đoán rằng tham số ref đã được sử dụng chỉ đơn giản là để ngăn chặn các lập trình viên từ đi qua những thứ khác hơn biến, chẳng hạn như Volatile.Read(2 + 3). Ai có thể thấy bất kỳ lý do nào khác cho số ref khi các biến được chuyển vào không?

+0

Vì nếu không bạn đang đọc một bản sao? –

+0

Có, nhưng điều đó có quan trọng không? Không phải rào cản bộ nhớ vẫn được chèn vào giữa việc đọc bản gốc và cách sử dụng tiếp theo của nó? – Douglas

Trả lời

9

Đó không phải là những gì mã thực trông giống như sau khi jitter được thực hiện với nó. Volatile.Read() là một nội tại. Một từ đắt tiền có nghĩa là jitter sẽ không biên dịch phương pháp nào cả, nhưng thay thế nó bằng phiên bản mã máy cụ thể của bộ vi xử lý. Mã bạn tìm thấy chỉ là một trình giữ chỗ có thể phục vụ như một dự phòng trên một máy mà không có một jitter đàng hoàng. Về mặt lý thuyết.

Bạn có thể xem những gì bạn nhận được trên máy của mình bằng Debug> Windows> Gỡ cài đặt. Bạn phải chuyển sang phiên bản Release và sử dụng Tools> Options> Debugging> General> untick "Suppress JIT optimization". Hầu hết các lập trình viên sẽ được hạnh phúc với những gì họ nhìn thấy:

04CF0450 mov   ecx,dword ptr ds:[7C43ACh] 

Hoặc nói cách khác: . Chỉ cần một bộ nhớ đơn giản đọc mà không có một rào cản. Intel/AMD lõi có một mô hình bộ nhớ mạnh mẽ mà không đòi hỏi một rào cản. Nhưng, nói, một lõi ARM làm và sẽ cần địa chỉ của biến. Itanium cũng yếu, nhưng jitter của nó đã bị ngưng.

Lưu ý làm thế nào, trong khi bạn có thể hạnh phúc, đây cũng là tin xấu. Về cơ bản, bạn không thể dựa vào thử nghiệm chương trình của bạn trên máy tính của bạn và kết luận nó là đủ tốt. Hay nói cách khác, không có cách nào để nói rằng bạn nên sử dụng Volatile nhưng bạn đã quên. Chỉ chạy chương trình của bạn trên thiết bị là sẽ cho bạn một gợi ý rằng bạn đã nhận nó sai. Phải mất rất nhiều can đảm để bỏ qua lock :)

Một số nội tại khác xung quanh như vậy, Math.Sqrt() chẳng hạn. Hầu hết các bộ xử lý có nó như là một hướng dẫn mã máy tích hợp.

+0

Cảm ơn lời giải thích tuyệt vời! Tuy nhiên, một kiến ​​trúc yếu như ARM có thực sự cần địa chỉ của biến không? Đọc linh hoạt chỉ nên được dự kiến ​​để ngăn chặn sắp xếp lại các hoạt động bộ nhớ mà đến sau họ, không phải trước đây. Vì vậy, 'Volatile.Read' không cần phải làm bất cứ điều gì ngoài việc chèn một rào cản bộ nhớ giữa cuộc gọi của nó và các tập quán tiếp theo của biến, ngay cả trên các kiến ​​trúc yếu. – Douglas

+1

Bạn luôn cần địa chỉ của biến để đọc biến động, 0x7C43AC trong đoạn mã trên.Lưu ý cách nó không đáng kể ngăn cản bạn chuyển thuộc tính, điều đó không thể hoạt động và bạn sẽ gặp phải lỗi biên dịch thời gian thân thiện. Thay vì jitter phải tìm ra nó trong thời gian chạy là nó là một lvalue và tạo ra một ngoại lệ nếu nó không phải là. –

0

Bởi vì trong đối số .NET theo mặc định được chuyển bởi giá trị.

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