2015-05-16 11 views
6

Tôi hiểu từ khóa volatile trong C++ khá tốt. Nhưng trong C#, nó xuất hiện để có một ý nghĩa khác nhau, nhiều hơn như vậy liên quan đến đa luồng. Tôi nghĩ rằng hoạt động bool là nguyên tử, và tôi nghĩ rằng nếu hoạt động là nguyên tử, bạn sẽ không có mối quan tâm luồng. Tôi đang thiếu gì?Tại sao làm cho một bool dễ bay hơi khi đa luồng trong C#?

https://msdn.microsoft.com/en-us/library/x13ttww7.aspx

+1

'volatile' ngăn hướng dẫn sắp xếp lại xung quanh quyền truy cập biến. Nó khá phức tạp. Xem http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility – xanatos

+0

[Câu trả lời của Eric Lippert cho một câu hỏi khác] (http://stackoverflow.com/a/26315297/517852) thực sự có mô tả rất tốt về sự khác biệt trong ngữ nghĩa của biến động giữa C++ và C#. –

Trả lời

3

Từ khóa volatile trong C# là tất cả về đọc/viết sắp xếp lại, do đó, nó là một cái gì đó khá bí truyền.

http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility

(mà tôi cho là một trong những "kinh bổn" về luồng) viết:

Các từ khóa dễ bay hơi chỉ thị các trình biên dịch để tạo ra một Acquire hàng rào trên tất cả các đọc từ trường , và một hàng rào phát hành trên mỗi viết cho lĩnh vực đó.Một rào cản ngăn cản các lần đọc/ghi khác bị di chuyển trước hàng rào; một hàng rào phát hành ngăn cản các lần đọc/ghi khác bị di chuyển sau hàng rào. Những “nửa hàng rào” này nhanh hơn hàng rào đầy đủ bởi vì chúng cung cấp cho phạm vi thời gian chạy và phần cứng hơn để tối ưu hóa.

Nó là một cái gì đó khá đọc :-)

Bây giờ ... Những gì nó không có nghĩa là:

  • Nó không có nghĩa là một giá trị sẽ được đọc tại/sẽ được ghi tại

nó chỉ đơn giản có nghĩa là nếu bạn đọc một cái gì đó từ một biến không ổn định, tất cả mọi thứ el se đã được đọc/ghi trước khi đọc "đặc biệt" này sẽ không được di chuyển sau khi đọc "đặc biệt" này. Vì vậy, nó tạo ra một rào cản. Vì vậy, nghịch lý, bằng cách đọc từ một biến dễ bay hơi, bạn đảm bảo rằng tất cả các ghi bạn đã làm cho bất kỳ biến khác (dễ bay hơi hay không) tại thời điểm đọc sẽ được thực hiện.

Ghi dễ bay hơi có thể quan trọng hơn, và là thứ được bảo đảm một phần bởi CPU Intel và thứ gì đó không được đảm bảo bởi phiên bản Java đầu tiên: không viết lại sắp xếp lại. Vấn đề là:

object myrefthatissharedwithotherthreads = new MyClass(5); 

nơi

class MyClass 
{ 
    public int Value; 
    MyClass(int value) 
    { 
     Value = value; 
    } 
} 

Bây giờ ... biểu hiện có thể được tưởng tượng là:

var temp = new MyClass(); 
temp.Value = 5; 
myrefthatissharedwithotherthreads = temp; 

nơi temp được một cái gì đó được tạo ra bởi trình biên dịch mà bạn có thể' t thấy.

Nếu ghi có thể được sắp xếp lại, bạn có thể có:

var temp = new MyClass(); 
myrefthatissharedwithotherthreads = temp; 
temp.Value = 5; 

và thread khác có thể nhìn thấy một phần khởi MyClass, bởi vì giá trị của myrefthatissharedwithotherthreads có thể đọc trước lớp MyClass đã hoàn tất khởi tạo.

+1

Không chỉ là hàng rào, 'volatile' cũng ngăn chặn việc tối ưu hóa như truyền bá liên tục, loại bỏ mã chết hoặc đăng ký cẩu. Đó là hạn chế hơn so với hàng rào đơn giản xung quanh truy cập. –

+0

@Cicada Bạn có tham chiếu về điều này cho C# không? – xanatos

+0

Không, tôi không nghĩ đó là tiêu chuẩn. –

4

tôi nghĩ hoạt động bool là nguyên tử

Họ có thực sự nguyên tử.

và tôi nghĩ rằng nếu hoạt động là nguyên tử, bạn sẽ không có mối quan ngại về luồng.

Đó là nơi bạn có ảnh không hoàn chỉnh. Hãy tưởng tượng bạn có hai luồng chạy trên các lõi riêng biệt, mỗi luồng có các lớp bộ nhớ cache của riêng chúng. Chủ đề số 1 có số foo trong bộ nhớ cache và Chủ đề số 2 cập nhật giá trị foo. Chủ đề số 1 sẽ không thấy thay đổi trừ khi foo được đánh dấu là volatile, đã mua một số lock, sử dụng lớp Interlocked hoặc được gọi là Thread.MemoryBarrier(), điều này sẽ làm cho giá trị bị vô hiệu trong bộ nhớ cache. Do đó, guaranteeing that you read the most up to date value:

Sử dụng công cụ sửa đổi dễ bay hơi đảm bảo rằng một chuỗi sẽ truy lục giá trị mới nhất được ghi bởi chuỗi khác.

Eric Lippert có great post về biến động nơi ông giải thích:

Ngữ nghĩa đích thực của biến động đọc và viết là đáng kể phức tạp hơn tôi đã nêu ra ở đây; trong thực tế họ không thực sự đảm bảo rằng mọi bộ xử lý dừng lại những gì nó đang làm và cập nhật bộ nhớ cache đến/từ bộ nhớ chính. Thay vào đó, chúng cung cấp bảo đảm yếu hơn về cách truy cập bộ nhớ trước và sau khi đọc và viết có thể được quan sát để được đặt hàng đối với nhau.

Edit:

Theo nhận xét của @xanatos, Đây không có nghĩa rằng volatile đảm bảo một đọc ngay lập tức, nó đảm bảo đọc trên giá trị được cập nhật nhất.

+0

Một phần sai. một ký tự 'volatile' không đảm bảo viết ngay lập tức. – xanatos

+0

@xanatos Tôi không có nghĩa là nó đảm bảo viết ngay lập tức. Tôi nghĩ nó đảm bảo một đọc trên giá trị cập nhật. –

+0

Bạn có vấn đề bằng văn bản 'volatile' :-) Hai lần viết, hai lần sai :-) :-) – xanatos

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