Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is accessing a tuple of tuples of pointers and a mutexes thread-safe

Given the std::tuple,

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;

And the function,

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)
}

According to this question on SO accessing a std::tuple is not inherently thread-safe, but what about in the case of the example code? Is it possible for undefined/strange things to happen?

This is assuming FooN & BarN are only ever accessed after the lock.

like image 435
Babar Shariff Avatar asked Oct 18 '22 11:10

Babar Shariff


1 Answers

Quoting from the perfect answer to the question you linked:

However, if the parameter were const, then get would not be considered to provoke a data race with other const calls to get.

This is basically your answer. Make each and every get call (on any tuple that's not completely protected by a mutex) on a const tuple and you're safe.

This means your code as posted is not safe. Modify like so:

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)
}

Currently the only solution I see is using a tuple like:

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

The required const will stick to everything (except pointer targets).

like image 81
Daniel Jour Avatar answered Oct 27 '22 11:10

Daniel Jour