Tôi có thể, không khóa, gọi an toàn List.AddRange (r) từ nhiều luồng không? Nếu không, tôi sẽ gặp rắc rối gì?Chủ đề Danh sách <T> .AddRange() có an toàn không?
Trả lời
Không, its documentation không nói đó là luồng an toàn, do đó không phải là chủ đề an toàn.
Tĩnh công cộng (Được chia sẻ trong Visual Basic) thành viên thuộc loại này là 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.
Như những gì có thể đi sai, suy nghĩ về những gì AddRange (newItems) thực hiện:
- Kiểm tra xem có đủ không gian trong mảng nội
- Nếu không:
- Phân bổ mảng mới
- Sao chép các mục hiện tại vào mảng mới
- Đặt trường để trỏ đến mảng mới ay
- Sao chép newItems đến đúng các địa phương trong mảng nội
- Cập nhật các “đếm” lĩnh vực (điều này được sử dụng để kiểm soát nơi mục tiếp theo được chèn)
Bây giờ nghĩ điều gì sẽ xảy ra nếu ở trên được trộn lẫn với một cuộc gọi đến AddRange() hoặc thậm chí chỉ là một cuộc gọi để đọc một mục.
Không có chuỗi không an toàn.
Chủ đề A có thể gọi AddRange trong danh sách của bạn. Nó có thể lặp lại một phần trong bộ sưu tập và chuyển đổi chủ đề.
Chủ đề B có thể gọi Thêm/Xóa, v.v. trước khi Chủ đề A kết thúc.
Không, nhưng tôi muốn thêm hiệu quả hơn là thực hiện myList.AddRange(...);
trong vòng khóa hơn là thực hiện một số lock (syncLock) { myList.Add(...) };
.
Bạn gặp phải sự cố nào? Khi một chủ đề đang thêm một mục trong khi một chủ đề khác liệt kê danh sách, List<T>
sẽ ném một ngoại lệ nhất định vì nó thực hiện một số phiên bản nội bộ, vì nó muốn ngăn chặn chúng tôi phát triển kém.
Ngoài ra, List<T>
sẽ giữ một mảng trong đó lưu trữ các mục của nó. Có thể thiết lập một mục trong một mảng là khá nguyên tử, nhưng bất cứ khi nào công suất của mảng này được đạt tới, một cái mới sẽ được tạo ra và các mục sẽ được sao chép từ cái cũ. Vì vậy, khi một chủ đề muốn thêm một cái gì đó trong khi sao chép diễn ra, bạn có thể tưởng tượng rằng mọi thứ sẽ đi ra khỏi đồng bộ.
Câu trả lời tuyệt vời, cảm ơn. =) –
Cho đến .NET Framework 4.0, không có bộ sưu tập .NET nào an toàn. Sau đó, bạn sẽ được yêu cầu khóa nó trước khi bạn truy cập nó trong mã số
Collections and Synchronization (Thread Safety)
.
Mặt khác, .NET Framework 4.0 giới thiệu không gian tên System.Collections.Concurrent
mới bao gồm chi tiết Thread-Safe Collections
.
Cuối cùng, nếu bạn có thể sử dụng .NET Framework 4.0, tôi khuyên bạn nên làm như vậy cho những gì bạn cần, nếu không, hãy nhớ khóa bộ sưu tập mỗi khi bạn muốn sửa đổi hoặc truy cập nó.
Bên cạnh đó, bộ sưu tập tĩnh phải an toàn cho luồng, nhưng hãy cẩn thận vì các thành viên không được đảm bảo.
EDIT # 1
Sau khi xác minh thêm do bình luận Steve Townsend, tôi thừa nhận rằng có ba bộ sưu tập thread-safe trong .NET Framework bắt đầu với phiên bản 3.0:
- SynchronizedCollection Generic Class;
- SynchronizedKeyedCollection Generic Class;
- SynchronizedReadOnlyCollection Generic Class.
Tôi xin lỗi, tôi vừa mới biết được bản thân mình. =)
không đúng, có một số trong 'System.Collections.Generic' hoạt động ở đây và đặt trước 4.0 –
@Steve Townsend: Sau khi xác minh, bạn nói đúng, tôi sai. Bên cạnh đó, bộ sưu tập chung 'IList
Không sao cả. Tôi nợ bạn một +1 để đề cập đến bộ sưu tập 4.0. –
Tùy thuộc vào mức sử dụng của bạn, SynchronizedCollection có thể hoạt động.
Mặc dù bạn sẽ không có một lần chụp AddRange
. Nếu bạn chỉ sử dụng điều này để thu thập bộ sưu tập, bạn có thể làm điều này vì có quá tải khởi tạo IEnumerable
.
+1 Tôi vừa học được điều gì đó mới mẻ ngay hôm nay! Cảm ơn! =) –
Cảm ơn bạn đã upvote. Tôi muốn cho bạn biết rằng tôi đã chỉnh sửa câu trả lời của tôi để phản ánh thông tin mới này mà bạn đã cung cấp cho tôi (tất cả chúng tôi). –
btw - re 'loại rắc rối nào?' - bạn sẽ có thể nhận được một ngoại lệ, tại một số thời điểm ngẫu nhiên khi nhiều chủ đề xung đột –