The following block of code:
Is technically invalid, since
std::get<>()
is not thread safe. Reference: Is using `std::get<I>` on a `std::tuple` guaranteed to be thread-safe for different values of `I`?As far as I can tell, is effectively safe on all implentations of
std::tuple<>
in the wild right now, and the foreseeable future.
#include <tuple>
#include <atomic>
#include <thread>
// Out of my control
using data_t = std::tuple<int, int, int, int>;
void foo(data_t);
//
int main() {
data_t landing;
std::atomic<int> completed = 0;
// Whichever thread pings last will be the one performing foo()
auto ping = [&](){
if(++completed == 4) {
foo(landing);
}
};
std::thread a([&](){ std::get<0>(landing) = 1; ping(); });
std::thread b([&](){ std::get<1>(landing) = 2; ping(); });
std::thread c([&](){ std::get<2>(landing) = 3; ping(); });
std::thread d([&](){ std::get<3>(landing) = 4; ping(); });
a.join();
b.join();
c.join();
d.join();
return 0;
}
To make matters even more fun, the actual code in question is chock-full of variadic templates, so writing a one-shot landing pad struct to handle that one scenario is not going to cut it. It has to be a general solution.
My current options are:
- Effectively re-implement
std::tuple<>
with a rewordedstd::get<>
documentation, which is a waste of time and a waste of code. - Push a proposal for
std::get<>(std::tuple)
to provide guarantees similar tostd::vector<>
, and document the fact that the code is only valid as of a yet unreleased verion of the standard. - ignore the issue, and rely on the fact that realistically, this will almost certainly always work.
None of those are particularly great in the short run... So my questions are:
- Did I miss something that invalidates point #2?
- Is there a better workaround that would allow the implementation to be technically valid while not having to support an excessive amount of extra code.
- Any other opinions on the subject are welcome.