2010-05-12 17 views
12

Tôi đang lập kế hoạch tạo danh sách một lần trong một hàm dựng tĩnh và sau đó có nhiều phiên bản của lớp đó đọc nó (và liệt kê qua nó) đồng thời mà không thực hiện bất kỳ khóa nào.An toàn chủ đề của C# Danh sách <T> cho người đọc

Trong bài viết này http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx MS mô tả các vấn đề an toàn chủ đề như sau:

tĩnh công cộng (chung trong Visual Basic) thành viên của loại này là chủ đề an toàn. Bất kỳ thành viên nào không phải là được đảm bảo là chuỗi an toàn.

Danh sách có thể hỗ trợ nhiều độc giả đồng thời, miễn là bộ sưu tập không được sửa đổi. Liệt kê thông qua một bộ sưu tập là về bản chất không phải là thủ tục an toàn thread . Trong trường hợp hiếm hoi khi một số đếm cạnh tranh với một hoặc nhiều hơn quyền truy cập ghi, cách duy nhất để đảm bảo an toàn chủ đề là khóa bộ sưu tập trong toàn bộ số liệt kê. Để cho phép bộ sưu tập được truy cập bằng nhiều luồng cho việc đọc và viết , bạn phải triển khai đồng bộ hóa của riêng mình.

"Việc đếm qua bộ sưu tập thực chất không phải là quy trình an toàn chỉ." Tuyên bố là điều khiến tôi lo lắng.

Điều này có nghĩa rằng đó là chủ đề an toàn cho độc giả chỉ có kịch bản, nhưng miễn là bạn không sử dụng điều tra?

Hoặc có an toàn cho kịch bản của tôi không?


Cảm ơn câu trả lời. Tại sao tôi cần sử dụng AsReadOnly nếu nó hoạt động khi có hoặc không có nó?

Trả lời

1

Điều này có nghĩa rằng đó là chủ đề an toàn cho độc giả chỉ kịch bản, nhưng miễn là khi bạn không sử dụng điều tra? Hoặc là nó có an toàn cho kịch bản của tôi không?

Phụ thuộc hoàn toàn vào thời điểm bạn ghi vào bộ sưu tập. Điều đó không thể trùng với đọc (liệt kê) mà không có một số loại chương trình khóa.

Vì vậy, nếu bạn điền vào một lần và sau đó chỉ lặp lại, bạn sẽ an toàn. Nhưng khi một chủ đề thay đổi danh sách (thêm hoặc xóa các mục), bạn sẽ cần ví dụ như một ReaderWriterLockSlim.

Khi bạn thay đổi trạng thái của mục được lưu trữ, chủ đề an toàn là với mục đó (không phải danh sách).

8

Có nghĩa là nếu bạn liệt kê một bộ sưu tập trong khi một chủ đề khác (hoặc chủ đề của riêng bạn) thay đổi nó, bạn sẽ gặp sự cố.

Miễn là bạn không thay đổi bộ sưu tập nào cả, và miễn là bạn không chia sẻ IEnumerator trên các chủ đề, bạn không nên gặp bất kỳ sự cố nào.

+0

Bởi 'không chia sẻ IEnumerators qua chủ đề' bạn có nghĩa là 'không truy cập ** cùng một điều tra dụ ** từ nhiều chủ đề'? –

+1

@EugeneBeresovksy: Chính xác. – SLaks

3

Có, danh sách này an toàn cho độc giả chỉ trường hợp, nếu danh sách sẽ không bao giờ được sửa đổi thì sẽ ổn.

Nếu thực tế là sau khi xây dựng danh sách sẽ không bị sửa đổi, thì bạn nên sử dụng giao diện phù hợp hơn như ReadOnlyCollection. nếu nó được lưu trữ trong một biến tĩnh công cộng như bạn nói bạn nên sử dụng giao diện đó.

private static List<T> shared_list; 

private static ReadOnlyCollection<T> _data; 
public static IEnumerable<T> Data 
{ 
    get 
    { 
     return _data ?? (_data = shared_list.AsReadOnly()); 
    } 
} 

==== EDIT ====

Phiên bản này lưu trữ các tài liệu tham khảo ReadOnlyCollection cho lần tra cứu tương lai nhanh hơn. Lưu ý, có một khả năng cho một cuộc đua dữ liệu xảy ra trên biến _data nếu hai chủ đề cố gắng lấy một tham chiếu đồng thời khi nó là null, nhưng bởi vì mọi thứ chỉ đọc này không thực sự quan trọng, chúng ta sẽ chỉ tạo một đối tượng ReadOnlyCollection bổ sung, rẻ hơn so với đồng bộ hóa.

+0

Lưu ý rằng bạn vẫn không được thay đổi danh sách gốc. Ngoài ra, không gọi 'AsReadOnly' mỗi lần bạn nhận được tài sản. – SLaks

+0

AsReadOnly là một hoạt động O (1) theo tài liệu MSDN. Tôi tin rằng nó chỉ đơn giản là kết thúc tốt đẹp với một ReadOnlyCollection mà chỉ đơn giản là đại biểu cho bộ sưu tập cơ bản. Vì vậy, AsReadOnly nên được khá nhanh chóng, nhưng nó gây ra một phân bổ để chúng tôi có khả năng có thể chia sẻ bộ nhớ đó. chỉnh sửa để phản ánh. – luke

+0

Dưới .NET 4 bạn có thể sử dụng lớp Lazy chung để khởi tạo. Xem http://msdn.microsoft.com/en-us/library/dd642329.aspx – TrueWill

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