2009-09-01 33 views
30

Tôi có một câu hỏi về an toàn luồng của std :: set.Là C++ std :: đặt thread-safe?

Theo như tôi biết tôi có thể lặp qua tập hợp và thêm/xóa thành viên và điều đó không làm mất hiệu lực trình vòng lặp.

Nhưng xem xét sau đây kịch bản:

  • chủ đề 'A' lặp trên một tập hợp các shared_ptr < Loại>
  • chủ đề 'B' thỉnh thoảng bổ sung thêm các mục vào thiết lập này.

Tôi đã trải nghiệm các segfaults khi chương trình chạy và tôi không chắc chắn tại sao điều này xảy ra. Thiếu an toàn chủ đề có phải là nguyên nhân không?

Trả lời

9

Không có hộp chứa STL nào là chỉ an toàn, do đó, std::set nói riêng thì không.

Trong trường hợp của bạn, vấn đề thậm chí không thực sự an toàn cho luồng: Bạn chỉ cần chia sẻ một đối tượng trên nhiều luồng (tốt) và sửa đổi nó trong một chuỗi (cũng được). Nhưng như bạn đã nói, việc sửa đổi vùng chứa sẽ làm mất hiệu lực các trình vòng lặp của nó. Việc điều này xảy ra trong cùng một chuỗi hoặc trong một chuỗi khác không có hậu quả vì nó vẫn là cùng một vùng chứa.

D'oh! §23.1.2.8 nói rằng chèn không làm mất hiệu lực các trình vòng lặp.

+9

cập nhật tập hợp không làm mất hiệu lực các trình vòng lặp ..... –

+0

Thực tế, trạng thái chuẩn bổ sung hoặc xóa khỏi tập hợp std :: không làm mất hiệu lực bất kỳ trình vòng lặp nào của nó (với trình vòng lặp trỏ đến đối tượng bị xóa là ngoại lệ rõ ràng). – suszterpatt

+0

Cảm ơn lời bình luận, tôi đã hoàn toàn thất bại. Mặc dù tôi phải nói, từ quan điểm của một người thực hiện, đây là một yêu cầu thực sự kỳ lạ. –

26

STL không có hỗ trợ chuỗi được xây dựng, vì vậy bạn sẽ phải mở rộng mã STL bằng cơ chế đồng bộ hóa của riêng bạn để sử dụng STL trong môi trường đa luồng.

Ví dụ xem ở đây: link text

Kể từ khi thiết lập là một lớp container MSDN đã sau đây để nói về chủ đề an toàn của container.

Một đối tượng duy nhất là chủ đề an toàn để đọc từ nhiều chủ đề. Ví dụ, cho một đối tượng A, nó là an toàn để đọc A từ thread 1 và từ thread 2 cùng một lúc.

Nếu một đối tượng duy nhất được ghi vào một chuỗi, thì tất cả các lần đọc và ghi vào đối tượng đó trên cùng một luồng hoặc các chủ đề khác phải được bảo vệ. Ví dụ, cho một đối tượng A, nếu thread 1 được viết cho A, thì thread 2 phải được ngăn chặn từ việc đọc hoặc ghi vào A.

Đọc và ghi an toàn cho một thể hiện của một loại ngay cả khi một loại khác chuỗi đang đọc hoặc ghi vào một thể hiện khác cùng loại. Ví dụ, các đối tượng A và B cùng loại, sẽ an toàn nếu A đang được viết trong chủ đề 1 và B đang được đọc trong chủ đề 2.

+8

Trên thực tế, bạn sẽ thấy dễ dàng hơn khi tạo một lớp an toàn chủ đề có chứa std :: set thay vì mở rộng tập hợp chính nó. CÁCH làm việc ít hơn. – Kieveli

+4

@Kieveli +1, nhưng bạn phải cẩn thận không cung cấp backdoors vào bộ lặp (set set iterators) và có thể ngụ ý phải viết bộ lặp của riêng bạn trên đầu lặp bộ để các gia số/decrements là thread an toàn . Không triển khai bộ an toàn luồng cũng như trình bao bọc là các tác vụ đơn giản ... –

+0

Bạn có thể cung cấp liên kết đến trích dẫn MSDN không? NEVERMIND: http://msdn.microsoft.com/en-us/library/c9ceah3b(v=VS.100).aspx –

19

Tài liệu STL Dinkumware chứa đoạn follwing về chủ đề đó. Nó có thể (như được chỉ ra trong văn bản) hợp lệ cho hầu hết các triển khai.

Đối với các đối tượng chứa quy định tại Standard ++ Thư viện C, chẳng hạn như STL Container và các đối tượng của mẫu lớp basic_string, thực hiện này sau rộng rãi thực hành thông qua nêu ra cho SGI STL:

Nhiều chủ đề có thể đọc một đối tượng chứa cùng một cách an toàn. (Có các đối tượng phụ có thể thay đổi không được bảo vệ trong phạm vi đối tượng chứa.)

Hai chủ đề có thể thao tác an toàn các đối tượng container khác nhau cùng loại. (Hiện tại không có không được bảo vệ đối tượng tĩnh chia sẻ trong một container loại.)

Bạn phải bảo vệ chống truy cập đồng thời để một container đối tượng nếu có ít nhất một thread là sửa đổi đối tượng. (Rõ ràng nguyên thủy đồng bộ hóa, chẳng hạn như những người trong Dinkum Chủ đề Thư viện, sẽ không bị phá vỡ bởi các đối tượng container .)

Vì vậy, không có nỗ lực được thực hiện để đảm bảo rằng hoạt động nguyên tử trên container đối tượng là chủ đề an toàn; nhưng nó là đủ dễ dàng để làm cho vùng chứa được chia sẻ các đối tượng có chủ đề an toàn ở mức độ chi tiết thích hợp .

1

Giải thích đơn giản: Nếu chuỗi A đang di chuyển vòng lặp qua vùng chứa, nó đang xem nội dung vùng chứa. Nếu luồng B sửa đổi vùng chứa (ngay cả một thao tác không làm mất hiệu lực trình lặp mà A có), thì luồng A có thể gặp rắc rối vì B đang lừa với nội bộ của thùng chứa, có thể có chúng trong trạng thái không hợp lệ (tạm thời). Điều này gây ra sự cố trong chủ đề A.

Vấn đề KHÔNG phải là bản thân trình vòng lặp. Nó khi họ cần cấu trúc dữ liệu của container để tìm vị trí mà bạn gặp rắc rối.

Đơn giản như vậy.

0

Có. Một cách để xử lý tình huống này là để mỗi thread khóa một mutex chia sẻ trước khi truy cập vào cùng một đối tượng đã đặt. Đảm bảo bạn sử dụng kỹ thuật RAII để khóa và mở khóa mutex.

0

Thực hiện chèn có thể khiến vectơ phân bổ lại bộ nhớ cơ bản của nó trong khi trình vòng lặp vẫn có thể trỏ đến địa chỉ bộ nhớ trước đó (nhưng không hợp lệ), dẫn đến lỗi phân đoạn.

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