2009-04-10 24 views
10

Hiểu biết của tôi là nếu bạn đang sử dụng danh sách chung (Danh sách) trong C#, nó có thể hỗ trợ nhiều người đọc đồng thời nhưng chỉ có một người viết. Và khi bạn giới thiệu một nhà văn vào bản mix, bạn cũng phải cung cấp các cấu trúc đồng bộ hóa để làm cho thread hoạt động được an toàn.là danh sách <T> .Contains() cuộc gọi Threadafe - C#

List.Contains có được coi là hoạt động đọc không? Nói cách khác, nếu tôi gọi phương thức này, tôi có cần phải lo lắng rằng một người viết có thể đang viết vào Danh sách này cùng một lúc không?

+0

Hãy suy nghĩ về cách hoạt động của hàm. Nó rất có thể sử dụng một vòng lặp for (hoặc cái gì khác nếu đó là một danh sách được sắp xếp) mà có thể dễ dàng kiểm tra một giá trị ngoài ranh giới mảng nếu một cuộc gọi Danh sách .Remove() được thực hiện đồng thời. Kết quả trong một "Chỉ số mảng ngoài ranh giới". ngoại lệ bị ném. –

Trả lời

23

Có, bạn nên làm như vậy. Về cơ bản tôi sẽ đồng bộ hóa cho bất kỳ hoạt động nào nếu danh sách có thể được sử dụng để viết cùng một lúc.

Nói chung tôi tìm thấy các bộ sưu tập được chia thành hai loại - được tạo ra, được khởi tạo và sau đó không bao giờ thay đổi nữa (chỉ an toàn) và các bộ lọc bị biến đổi theo thời gian (không an toàn thread, khóa cho mọi truy cập).

+5

Trong trường hợp bạn khởi tạo một, điền vào nó, và không bao giờ sử dụng nó một lần nữa, tôi thấy nó rất hữu ích để bọc nó trong một ReadOnlyCollection (). Nó không ngăn một người tiêu dùng đột biến các mục cơ bản trong bộ sưu tập, nhưng nếu bạn vứt bỏ tham chiếu đến danh sách gốc, thì việc lặp lại là an toàn. –

+0

Scott: Đồng ý - điều đó làm cho nó rõ ràng hơn rất nhiều. Cá nhân tôi thích sử dụng các loại bộ sưu tập đảm bảo tính bất biến ngay sau khi xây dựng (sử dụng loại trình xây dựng nếu cần) nhưng không có sẵn trong khung cốt lõi: ( –

2

List<T>.Contains chắc chắn là hoạt động đọc. Có thể một số chủ đề khác đang ghi vào bộ sưu tập khi bạn đọc nó.

+0

Và nếu bộ sưu tập thay đổi trong khi Contains đang chạy? –

+0

Nevermind, tốt bây giờ –

1

Theo doc ...

Tiến hành thống kê thông qua một bộ sưu tập là bản chất không phải là một thủ tục thread-safe.

Vì vậy, tôi sẽ nói không có chuỗi nào không an toàn. Bạn nên khóa nó.

0

Nếu một nhà văn có thể viết cùng một lúc, List.Contains chắc chắn không phải là chủ đề an toàn. Bạn sẽ cần phải quấn nó và bất kỳ lần đọc và viết khác bằng khóa.

2

Có, bạn phải lo lắng! List.Contains chỉ nhận EqualityComparer và sau đó lặp qua tất cả các mục trong danh sách chứa so sánh mục được truyền như tham số với mục tại chỉ mục của phép lặp hiện tại, vì vậy nếu danh sách bị sửa đổi trong khi được lặp lại, kết quả có thể không thể đoán trước.

1

Có thể giả định đây không phải là thao tác an toàn trên luồng. Các MSDN description tiền nó lên:

... Phương pháp này sử dụng Equals của bộ sưu tập đối tượng và phương pháp CompareTo trên mục để xác định xem mục tồn tại.

Vì vậy, sau thao tác đọc là thao tác so sánh.

1

Trong môi trường nhiều luồng, bạn cần đảm bảo không có văn bản nào cho bộ sưu tập cùng một lúc. Đây là mã từ phản xạ, bản thân bộ sưu tập không cung cấp bất kỳ khóa nào cho bạn, do đó, đó là chiến thắng của bạn.

public bool Contains(T item) 
{ 
    if (item == null) 
    { 
     for (int j = 0; j < this._size; j++) 
     { 
      if (this._items[j] == null) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 
    EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
    for (int i = 0; i < this._size; i++) 
    { 
     if (comparer.Equals(this._items[i], item)) 
     { 
      return true; 
     } 
    } 
    return false; 
} 
+0

+1 cho suy nghĩ tuyệt vời như nhau) –

0

Nó được coi là một hoạt động đọc. Bạn sẽ không gặp phải bất kỳ điều kiện chủng tộc nào nhưng nếu bạn lo ngại về việc nhận được thông tin mới nhất, bạn có thể thực hiện Listvolatile.

0

Theo the MSDN documentation:

Công tĩnh (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 cá thể nào cũng không được bảo đảm là luồng an toàn.

Lớp ReaderWriterLock dường như được xây dựng cho đồng bộ hóa mà bạn đang tìm kiếm.

4

Nếu bạn sử dụng Reflector để kiểm tra tại mã này, bạn sẽ có được một cái gì đó như thế này:

public bool Contains(T item) 
    { 
     if (item == null) 
     { 
      for (int j = 0; j < this._size; j++) 
      { 
       if (this._items[j] == null) 
       { 
        return true; 
       } 
      } 
      return false; 
     } 
     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
     for (int i = 0; i < this._size; i++) 
     { 
      if (comparer.Equals(this._items[i], item)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

Như bạn có thể thấy, nó là một sự lặp lại đơn giản so với các mặt hàng mà chắc chắn là một 'đọc' hoạt động. Nếu bạn đang sử dụng nó chỉ cho lần đọc (và không có gì đột biến các mục), sau đó không cần phải khóa. Nếu bạn bắt đầu sửa đổi danh sách trong một chuỗi riêng biệt, thì bạn nhất thiết phải đồng bộ hóa quyền truy cập.

+0

Điều đó có vẻ sai. là một hoạt động đọc, bạn vẫn đang quay cuồng trên biến _size và trên các chỉ mục trong một mảng bên trong đây chính xác là loại địa điểm ngoại lệ bị ràng buộc có thể bị ném ra khỏi. @JonSkeet? –

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