2011-12-18 36 views
5

Giản câu hỏi để cung cấp cho một đại diện rõ ràng hơn về những gì tôi đang thực sự yêu cầumảng của các đối tượng, cập nhật trong một thread và đọc trong một

Tôi có hai chủ đề, gọi cho họ AB. Họ chia sẻ một đối tượng thuộc loại Foo có một trường được gọi là Name và được lưu trữ trong một loại loại Foo[] tại chỉ số 0. Các chủ đề sẽ luôn truy cập chỉ mục 0 theo thứ tự được đảm bảo bởi hệ thống đã sẵn sàng, do đó không có điều kiện chủng tộc nào của chủ đề B nhận trước chủ đề A.

Đơn đặt hàng này.

// Thread A 
array[0].Name = "Jason"; 

// Thread B 
string theName = array[0].Name 

Như tôi đã nói lệnh này đã được đảm bảo, có có cách nào cho thread B để đọc các giá trị trước khi sợi Một

Những gì tôi muốn đảm bảo là hai điều:

  1. Cả hai chuỗi đều nhận được đối tượng mới nhất tại chỉ mục 0.
  2. Chủ đề B luôn nhận giá trị mới nhất trong trường .Name

Đánh dấu Name là dễ bay hơi không phải là một tùy chọn, vì các đối tượng thực sự phức tạp hơn nhiều và thậm chí có các cấu trúc tùy chỉnh mà thậm chí không thể có thuộc tính dễ bay hơi gắn liền với chúng.

Bây giờ, đáp ứng 1 là dễ dàng (luôn luôn nhận được đối tượng mới nhất), bạn có thể làm một .VolatileRead:

// Thread A 
Foo obj = (Foo)Thread.VolatileRead(ref array[0]); 
obj.Name = "Jason"; 

// Thread B 
Foo obj = (Foo)Thread.VolatileRead(ref array[0]); 
string theName = obj.Name 

Hoặc bạn có thể chèn một rào cản bộ nhớ:

// Thread A 
array[0].Name = "Jason"; 
Thread.MemoryBarrier(); 

// Thread B 
Thread.MemoryBarrier(); 
string theName = array[0].Name 

Vì vậy, câu hỏi của tôi là: Điều này có đủ để thỏa mãn điều kiện 2 không? Rằng tôi luôn luôn nhận được giá trị mới nhất từ ​​các lĩnh vực của đối tượng tôi đọc ra? Nếu đối tượng tại chỉ mục 0 chưa thay đổi, nhưng Name có. Sẽ thực hiện một số VolatileRead hoặc MemoryBarrier trên chỉ mục 0 đảm bảo tất cả các trường trong đối tượng tại chỉ mục 0 cũng sẽ nhận được giá trị mới nhất của chúng?

+1

Tại sao bạn sử dụng mảng? Nhìn vào không gian tên ['System.Collections.Concurrent'] (http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx). – Oded

+0

Không sử dụng .NET4, để bắt đầu. Và các công cụ đồng thời, theo như tôi biết, chỉ đảm bảo nội dung của các bộ sưu tập và không cho các trường/thuộc tính có thể có của các đối tượng trong bộ sưu tập. – thr

+0

Tôi không nghĩ rằng dễ bay hơi sẽ đảm bảo những gì bạn nghĩ rằng nó sẽ. –

Trả lời

2

Không có giải pháp nào trong số này, lock hoặc volatile sẽ giải quyết được sự cố của bạn. Bởi vì:

  1. volatile đảm bảo rằng các biến thay đổi bởi một thread có thể nhìn thấy ngay lập tức để đề khác hoạt động trên cùng một dữ liệu (ví dụ: họ không được cache) và cũng là hoạt động trên biến mà không được sắp xếp lại. Không thực sự những gì bạn cần.
  2. lock đảm bảo rằng việc ghi/đọc không xảy ra đồng thời nhưng không đảm bảo đơn đặt hàng của họ. Nó phụ thuộc vào chủ đề nào có được khóa đầu tiên, đó là không xác định.

Do đó, nếu dòng chảy của bạn là:

Thread A read Name 
Thread A modify Name 
Thread B read Name 

chính xác theo thứ tự đó, bạn sẽ cần phải thực thi nó với một sự kiện (ví dụ AutoresetEvent ví dụ):

//Thread A 
foo[0].Name = "John"; // write value 
event.Set(); // signal B that write is completed 

//Thread B 
event.WaitOne(); // wait for signal 
string name = foo[0].Name; // read value 

Sự bảo đảm này thread B không đọc biến Name cho đến khi A sửa đổi nó.

Chỉnh sửa: Ok, vì vậy bạn chắc chắn rằng luồng trên được tôn trọng. Vì bạn đang nói rằng bạn không thể khai báo các lĩnh vực volatile, tôi khuyên bạn nên sử dụng các Thread.MemoryBarrier() để giới thiệu hàng rào mà thi hành đặt hàng:

//Thread A 
foo[0].Name = "John"; // write value 
Thread.MemoryBarrier(); 

//Thread B 
Thread.MemoryBarrier(); 
string name = foo[0].Name; // read value 

Mọi chi tiết, kiểm tra tài liệu này: http://www.albahari.com/threading/part4.aspx

+0

Đây không phải là vấn đề, hai chủ đề không thể truy cập nó cùng một lúc. Không bao giờ. Tôi nghĩ mọi người hiểu sai câu hỏi của tôi và tôi cần phải viết lại nó. – thr

+0

Truy cập sẽ luôn luôn được tuần tự, nhưng từ hai (hoặc có thể nhiều hơn) các chủ đề khác nhau. – thr

+0

@thr: Từ tuyên bố này: "Bây giờ để có thể đảm bảo rằng Thread1 được giá trị mới được lưu trữ trong trường Tên của Foo ..." Tôi hiểu rằng bạn cần Thread1 để đọc Tên chỉ sau khi Thread0 được thực hiện cập nhật nó. – Tudor

0

Locks sẽ giải quyết vấn đề bạn có nếu tôi hiểu nó một cách chính xác. Điều này là do khóa tạo ra các rào cản bộ nhớ tiềm ẩn (đầy đủ) xung quanh chính nó.

Bạn cũng có thể sử dụng rào cản bộ nhớ một cách rõ ràng bằng cách sử dụng Thread.MemoryBarrier. Đọc thêm here. Hiệu ứng rào cản bộ nhớ có thể khá khó nhận thấy trên x86, nhưng trên hệ thống đặt hàng thoải mái hơn như PPC nó thường là đáng kể.

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