2012-01-04 32 views
19

Giả sử tôi có một lĩnh vực điều khiển thực hiện một số vòng lặp:Đây có phải là cách sử dụng đúng đắn của Thread.MemoryBarrier() không?

private static bool shouldRun = true; 

Và tôi có một sợi chạy, có mã như:

while(shouldRun) 
{ 
    // Do some work .... 
    Thread.MemoryBarrier(); 
} 

Bây giờ, thread khác có thể đặt shouldRun-false, mà không sử dụng bất kỳ cơ chế đồng bộ hóa nào.

Theo như tôi hiểu Thread.MemoryBarrier(), có cuộc gọi này bên trong vòng lặp while sẽ ngăn chặn chuỗi công việc của tôi nhận được phiên bản được lưu trong bộ nhớ cache shouldRun và ngăn chặn hiệu quả vòng lặp vô hạn xảy ra.

Sự hiểu biết của tôi về Thread.MemoryBarrier có đúng không? Cho tôi có chủ đề có thể đặt biến số shouldRun (điều này không thể dễ dàng thay đổi), đây có phải là cách hợp lý để đảm bảo rằng vòng lặp của tôi sẽ dừng sau khi shouldRun được đặt thành false bởi bất kỳ chuỗi nào?

+0

Không khai báo boolean như làm bay hơi giống nhau cả thôi? Tôi không chắc chắn về Thread.MemoryBarrier do đó bình luận không trả lời. ví dụ. http://www.albahari.com/threading/part4.aspxAnother> "một cách nâng cao hơn để giải quyết vấn đề này là áp dụng từ khóa dễ bay hơi vào trường _complete. Từ khóa dễ bay hơi chỉ thị trình biên dịch tạo ra một hàng rào có được trên mọi đọc từ lĩnh vực đó, và một hàng rào phát hành trên mỗi viết cho lĩnh vực đó ". Trân trọng, –

+3

Dễ bay hơi là một điều rất độc ác và không nên được sử dụng: http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part -three.aspx – Steven

+1

Lol, tôi không biết điều đó! Là một lập trình viên C/asm cũ, tôi nghĩ rằng đó là một điều tốt :) Cảm ơn bạn đã liên kết, tôi sẽ xem xét. –

Trả lời

26

Is này sử dụng đúng Thread.MemoryBarrier()?

No. Giả sử một chủ đề đặt cờ trước vòng lặp thậm chí bắt đầu thực thi. Vòng lặp vẫn có thể thực hiện một lần, sử dụng giá trị được lưu trong bộ nhớ cache của cờ. Có phải là chính xác không? Nó chắc chắn có vẻ không chính xác với tôi. Tôi hy vọng rằng nếu tôi thiết lập cờ trước khi thực hiện đầu tiên của vòng lặp, rằng vòng lặp thực hiện không lần, không một lần.

Theo như tôi hiểu Thread.MemoryBarrier(), có cuộc gọi này bên trong vòng lặp while sẽ ngăn luồng công việc của tôi lấy phiên bản được lưu trong bộ nhớ cache của shouldRun và ngăn chặn có hiệu quả vòng lặp vô hạn xảy ra. Sự hiểu biết của tôi về Thread.MemoryBarrier có đúng không?

Rào cản bộ nhớ sẽ đảm bảo rằng các xử lý không làm bất cứ reorderings của đọc và viết như vậy mà một truy cập bộ nhớ đó là logic trước rào cản thực sự là quan sát được sau nó, và ngược ngược lại.

Nếu bạn là địa ngục cúi đầu làm mã khóa thấp, tôi sẽ có khuynh hướng làm cho trường biến động hơn là giới thiệu một rào cản bộ nhớ rõ ràng. "dễ bay hơi" một tính năng của ngôn ngữ C#. Một tính năng nguy hiểm và kém hiểu, nhưng là một tính năng của ngôn ngữ. Nó rõ ràng giao tiếp với người đọc của mã rằng lĩnh vực trong câu hỏi sẽ được sử dụng mà không có khóa trên nhiều chủ đề.

đây có phải là cách hợp lý để đảm bảo rằng vòng lặp của tôi sẽ dừng lại một lần shouldRun được đặt thành false bởi bất kỳ chuỗi nào không?

Một số người sẽ coi nó là hợp lý. Tôi sẽ không làm điều này trong mã của riêng tôi mà không có một lý do rất, rất tốt.

Thông thường các kỹ thuật khóa thấp được chứng minh bằng các cân nhắc hiệu suất. Có hai cân nhắc như vậy:

Đầu tiên, khóa bị khóa có khả năng cực kỳ chậm; nó chặn miễn là có mã thực hiện trong khóa. Nếu bạn có một vấn đề về hiệu suất bởi vì có quá nhiều tranh chấp thì trước tiên tôi sẽ cố gắng giải quyết vấn đề bằng cách loại bỏ sự tranh chấp. Chỉ khi tôi không thể loại bỏ ganh đua, tôi sẽ đi đến một kỹ thuật khóa thấp.

Thứ hai, có thể là khóa không được giám sát quá chậm. Nếu "công việc" bạn đang làm trong vòng lặp mất ít hơn 200 nano giây thì thời gian cần thiết để kiểm tra khóa không bị khóa - khoảng 20 ns - là một phần đáng kể thời gian làm việc. Trong trường hợp đó tôi sẽ đề nghị bạn làm nhiều công việc hơn cho mỗi vòng lặp. Có thực sự cần thiết rằng vòng lặp dừng trong vòng 200 ns của cờ điều khiển được thiết lập?

Chỉ trong trường hợp cực đoan nhất về các tình huống hiệu suất, tôi có thể tưởng tượng rằng chi phí kiểm tra khóa không được kiểm soát là một phần đáng kể thời gian trong chương trình.

Và tất nhiên, nếu bạn đang gây ra rào cản bộ nhớ cứ sau 200 ns, bạn cũng có thể làm hỏng hiệu suất theo những cách khác. Bộ vi xử lý muốn để làm cho các tối ưu hóa bộ nhớ di chuyển-trong-thời gian di chuyển cho bạn; nếu bạn buộc phải liên tục từ bỏ những tối ưu hóa đó, bạn đang bỏ lỡ một chiến thắng tiềm năng.

2

Trong trường hợp này Thread.MemoryBarrier(); là một biến thể ít performant, nhưng không ít an toàn của

private static volatile readonly bool shouldRun = true; 

vì tuyên bố shouldRun như không ổn định sẽ thực hiện một rào cản bộ nhớ nếu điều này là cần thiết để đạt được một up-to-date đọc, nhưng có thể không cần phải làm như vậy.

3

Tùy thuộc vào những gì bạn đang cố gắng làm, điều này có thể sẽ không làm những gì bạn mong đợi. Từ MSDN, MemoryBarrier:

Đồng bộ hóa truy cập bộ nhớ như sau: Bộ xử lý thực hiện các chủ đề hiện tại không thể sắp xếp lại các hướng dẫn trong một cách mà bộ nhớ truy cập trước khi cuộc gọi đến MemoryBarrier thực hiện sau khi bộ nhớ các truy cập mà theo tiếng gọi vào MemoryBarrier.

Điều này sẽ ngăn việc sắp xếp lại hướng dẫn sau khi rào cản bộ nhớ gọi trước nó, nhưng điều đó sẽ không ngăn việc lập lịch trình chuỗi xác định vòng lặp phải lặp đi lặp lại trước khi chuỗi ghi thực sự thực hiện ghi, ví dụ: nó không phải là một cơ chế khóa hoặc đồng bộ hóa. Nó chỉ ngăn các hướng dẫn khác trong vòng lặp (như khởi tạo biến) được sắp xếp lại trước khi kiểm tra giá trị của shouldRun.

Tương tự như vậy, việc thoát khỏi điều này sẽ không gây ra vòng lặp vô hạn - trong cả hai trường hợp, shouldRun sẽ được kiểm tra với mọi lần lặp lại. Không có "giá trị được lưu trong bộ nhớ cache" tại đây.

+0

Miễn là không có đồng bộ hóa cụ thể cần thiết để _when_ Thread thấy shouldRun trở thành false, không cần bất kỳ hàng rào nào cả. Giá trị trường sẽ được quan sát để thay đổi cuối cùng; hàng rào chỉ là một vấn đề nếu có một yêu cầu cụ thể/quan sát của đọc và viết để cho hành vi chính xác xảy ra. –

7

Tôi tin rằng sự hiểu biết của bạn là một chút tắt trên dòng này

Theo như tôi hiểu Thread.MemoryBarrier(), có cuộc gọi này bên trong vòng lặp while sẽ ngăn chặn chủ đề công việc của tôi nhận được từ một phiên bản cache của các shouldRun, và có hiệu quả ngăn chặn một vòng lặp vô hạn xảy ra.

Rào cản bộ nhớ là cách thực thi ràng buộc đặt hàng trên hướng dẫn đọc/ghi. Trong khi kết quả đọc/ghi sắp xếp lại có thể có sự xuất hiện của bộ nhớ đệm một hàng rào bộ nhớ không thực sự ảnh hưởng đến bộ nhớ đệm trong bất kỳ cách nào.Nó chỉ đơn giản là hành động như một hàng rào mà trên đó đọc và viết hướng dẫn không thể vượt qua.

Trong mọi xác suất, điều này sẽ không ngăn chặn vòng lặp vô hạn. Có gì hàng rào bộ nhớ đang làm là kịch bản này là buộc tất cả các lần đọc và viết mà xảy ra trong cơ thể của vòng lặp xảy ra trước khi giá trị của shouldRun được đọc bởi các vòng lặp có điều kiện

Wikipedia has a nice walk through on memory barrier that you may find useful

3

Đây không phải là câu trả lời trực tiếp cho câu hỏi; tuy nhiên, điều đó dường như được đề cập tốt trong các bài đăng trên. Điều gì dường như không được nêu rõ là làm thế nào để đạt được kết quả mong muốn. Có thực sự là không có gì sai trái với chỉ sử dụng các chủ đề đối tượng đồng bộ nhằm mục đích:

private static readonly ManualResetEvent shutdownEvent = new ManualResetEvent(false); 

//Thread 1 - continue until event is signaled 
while(!shutodwnEvent.WaitOne(0)) 
{ 
    // Do some work .... 
    Thread.MemoryBarrier(); 
} 

//Thread 2 - signal the other thread 
shutdownEvent.Set(); 

Cách tiếp cận khác là sử dụng một tuyên bố khóa khi truy cập vào biến:

private static object syncRoot = new Object(); 
private static bool shouldRun = true; 

//Thread 1 
bool bContinue; 
lock(syncRoot) 
    bContinue = shouldRun; 

while(bContinue) 
{ 
    // Do some work .... 
    lock(syncRoot) 
     bContinue = shouldRun; 
} 

//Thread 2 
lock(syncRoot) 
    shouldRun = false; 
Các vấn đề liên quan