2017-06-13 17 views
5

Với std::tuple,là truy cập vào một tuple của các bộ của con trỏ và một mutexes thread-safe

using Tuple1 = std::tuple<Foo1*, Bar1*, std::shared_ptr<std::mutex>>; 
using Tuple2 = std::tuple<Foo2*, Bar2*, std::shared_ptr<std::mutex>>; 
std::tuple<Tuple1, Tuple2> tuple; 

Và chức năng,

void baz() 
{ 
    auto tup = std::get<0>(tuple); 

    std::lock_guard<std::mutex> lk(*std::get<2>(tup)); 

    // Do something with std::get<0>(tup) and std::get<1>(tup) 
} 

Theo this câu hỏi về SO truy cập vào một std::tuple không phải là vốn có chủ đề an toàn, nhưng trong trường hợp mã ví dụ thì sao? Có thể cho những điều không xác định/kỳ lạ xảy ra không?

Đây là giả định FooN & BarN chỉ được truy cập sau khi khóa.

+0

std :: không sửa đổi trạng thái của 'tuple', tôi không thể đảm bảo nhưng tôi chắc chắn nó sẽ hoạt động như thể bạn truy cập trực tiếp đối tượng bên dưới, có nghĩa là nếu đối tượng bên dưới là thread an toàn, hoạt động sẽ được (thực tế) thread an toàn. – Gizmo

Trả lời

3

Trích dẫn từ câu trả lời hoàn hảo cho câu hỏi bạn liên kết:

Tuy nhiên, nếu tham số là const, sau đó nhận được sẽ không được coi là kích động một cuộc chạy đua dữ liệu với const khác gọi để có được.

Đây chính là câu trả lời của bạn. Thực hiện từng cuộc gọi get (trên bất kỳ bộ t that'snh nào không phải là hoàn toàn được bảo vệ bởi một mutex) trên một bộ tảo const và bạn an toàn.

Điều này có nghĩa là mã của bạn đã được đăng không an toàn. Sửa đổi như sau:

void baz() 
{ 
    // vvvv just being explicit here 
    auto const & tup = std::get<0>(static_cast<decltype(tuple) const &>(tuple)); 

    std::lock_guard<std::mutex> lk(*std::get<2>(tup)); 

    // Dereference std::get<0>(tup) and std::get<1>(tup), 
    // use the pointed to objects at will, nothing else 

    // Not ok, because it could interfer with the call in initialisation of tup of another thread 
    // auto non_const_tup = std::get<0>(tuple) 
} 

Hiện nay giải pháp duy nhất tôi thấy là sử dụng một tuple như:

std::tuple< 
    std::shared_pointer<std::mutex>, 
    std::unique_pointer<std::tuple<Foo1*, Bar1*>> 
    // Mutex and pointer to tuple for Foo2 and Bar2 
    > 

Các yêu cầu const sẽ dính vào tất cả mọi thứ (trừ mục tiêu con trỏ).

+0

Nếu tôi hiểu chính xác, các con trỏ trong 'tup' không thể sửa đổi được và để sửa đổi chúng, tôi sẽ phải phản hồi lại tuple của chúng sau khi khóa? Ví dụ. 'auto tupMutable = std :: nhận được <0> (tuple)'. –

+0

No. Bạn vẫn có thể truy cập đồng thời vào 'tuple'. Tôi sẽ thêm một giải pháp. –

+0

Giải pháp tôi nghĩ ra là không chính xác. Tôi đoán bạn không muốn trỏ đến các thành viên 'tupleN'? –

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