2009-08-25 18 views

Trả lời

20

Bạn sử dụng volatile/Thread.MemoryBarrier() khi bạn muốn truy cập một biến trên các chuỗi mà không cần khóa. Ví dụ:

Biến là nguyên tử, chẳng hạn như int, luôn đọc và viết toàn bộ cùng một lúc. Điều đó có nghĩa là bạn sẽ không bao giờ nhận được một nửa giá trị trước khi một chủ đề khác thay đổi nó và một nửa khác sau khi nó đã thay đổi. Vì lý do đó bạn có thể đọc và ghi giá trị một cách an toàn trong các chủ đề khác nhau mà không cần đồng bộ hóa.

Tuy nhiên, trình biên dịch có thể tối ưu hóa một số lần đọc và ghi, mà bạn ngăn chặn bằng từ khóa volatile.Nếu bạn ví dụ có một vòng lặp như thế này:

sum = 0; 
foreach (int value in list) { 
    sum += value; 
} 

Trình biên dịch thực sự có thể làm các phép tính trong một thanh ghi bộ xử lý và chỉ viết những giá trị cho sum biến sau vòng lặp. Nếu bạn thực hiện biến số sumvolatile, trình biên dịch sẽ tạo mã đọc và ghi biến cho mọi thay đổi, để giá trị của nó được cập nhật trong suốt vòng lặp.

+1

+1, nhưng trong trường hợp nào thì vấn đề là trình biên dịch sẽ tạo mã đọc và ghi biến cho mọi thay đổi? – dtb

+0

Đó là chủ yếu là mong muốn khi luồng dtb, nếu không một sợi có thể có được một giá trị khác hơn so với khác và tất cả các loại điều điên rồ có thể xảy ra. – Skurmedel

+0

Vâng, đó hoặc sử dụng một rào cản bộ nhớ. – Skurmedel

10

Có gì sai với

private static readonly object syncObj = new object(); 
private static int counter; 

public static int NextValue() 
{ 
    lock (syncObj) 
    { 
     return counter++; 
    } 
} 

?

Điều này thực hiện tất cả các khóa, rào cản bộ nhớ, v.v. cần thiết cho bạn. Nó được hiểu rõ và dễ đọc hơn bất kỳ mã đồng bộ hóa tùy chỉnh nào dựa trên volatileThread.MemoryBarrier().


EDIT

Tôi không thể nghĩ ra một kịch bản trong đó tôi muốn sử dụng volatile hay Thread.MemoryBarrier(). Ví dụ

private static volatile int counter; 

public static int NextValue() 
{ 
    return counter++; 
} 

không tương đương với đoạn code trên và là không thread-safe (volatile không làm ++ kỳ diệu trở thành thread-safe).

Trong một trường hợp như thế này:

private static volatile bool done; 

void Thread1() 
{ 
    while (!done) 
    { 
     // do work 
    } 
} 

void Thread2() 
{ 
    // do work 
    done = true; 
} 

(mà nên làm việc) Tôi muốn sử dụng một ManualResetEvent để báo hiệu khi thread2 được thực hiện.

+0

Không có gì 'sai' với mã của bạn. Tôi đang cố gắng nắm bắt các tình huống trong đó dễ bay hơi và MemoryBarrier áp dụng. Như trong câu trả lời của Jon Skeet ở đây: http://stackoverflow.com/questions/395232/we-need-to-lock-a-net-int32-when-reading-it-in-a-multithreaded-code. – Alex

+0

.net cũng có một mô hình bộ nhớ khá nghiêm ngặt, chẳng hạn như đọc hoặc viết không thể thực hiện theo cách viết khác. –

+4

Mặc dù thông số ECMA có mô hình bộ nhớ khá yếu, vì vậy bạn có thể muốn xem nó, hãy xem http://www.bluebytesoftware.com/blog/2007/11/10/CLR20MemoryModel.aspx và http: // blog .msdn.com/cbrumme/archive/2003/05/17/51445.aspx –

10

Về cơ bản nếu bạn đang sử dụng bất kỳ loại đồng bộ hóa nào khác để làm cho luồng của bạn an toàn thì bạn không cần.

Hầu hết các cơ chế khóa (bao gồm khóa) tự động ngụ ý một hàng rào bộ nhớ để nhiều bộ xử lý có thể nhận được thông tin chính xác.

Dễ bay hơi và bộ nhớBarrier chủ yếu được sử dụng trong các trường hợp không có khóa, nơi bạn đang cố tránh hình phạt khóa hiệu suất.

Chỉnh sửa: Bạn nên đọc this article bởi Joe Duffy về mô hình bộ nhớ CLR 2.0, nó làm rõ rất nhiều thứ (nếu bạn thực sự quan tâm, bạn nên đọc TẤT CẢ bài viết từ Joe Duffie, người lớn nhất chuyên gia song song trong .NET)

+0

+1, nhưng điều đó hoàn toàn rõ ràng. Nếu bạn làm những gì dtb làm, dễ bay hơi/Thread.MemoryBarrier là không cần thiết. Cũng có những tình huống dễ bay hơi trên một thành viên không đủ. – Skurmedel

0

Như tên ngụ ý bảo đảm dễ bay hơi, giá trị bộ đệm được chuyển sang bộ nhớ sao cho tất cả các chuỗi đều thấy cùng giá trị. Ví dụ, nếu tôi có một số nguyên có ghi mới nhất được lưu trong bộ nhớ cache, các chủ đề khác có thể không thấy điều đó. Họ thậm chí có thể xem bản sao bộ nhớ cache của số nguyên đó. Đánh dấu một biến là dễ bay hơi làm cho nó được đọc trực tiếp từ bộ nhớ.

Sriwantha Sri Aravinda Attanayake

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