如何解决std :: get <>()缺乏并发性规范的问题

Fra*_*ank 12 c++ multithreading tuples language-lawyer c++17

以下代码块:

  1. 从技术上讲是无效的,因为std::get<>()不是线程安全的。参考:是否在`std :: tuple`上使用`std :: get <I>`保证对不同的`I`值是线程安全的?

  2. 据我所知,std::tuple<>现在和可预见的将来,在野外的一切努力实际上都是安全的。

    #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;
    }
Run Code Online (Sandbox Code Playgroud)

为了使事情变得更加有趣,实际的代码充满了各种各样的可变参数模板,因此编写一个一次性的着陆垫结构来处理一种情况不会减少它。它必须是一个通用的解决方案。

我当前的选择是:

  • std::tuple<>使用重新命名的std::get<>文档有效地重新实现,这既浪费时间又浪费代码。
  • std::get<>(std::tuple)提供类似于的保证提出建议std::vector<>,并记录该代码仅在该标准尚未发布的版本中有效。
  • 忽略该问题,并依靠一个事实,即几乎可以肯定,这将始终有效。

在短期内,这些都不是特别出色...所以我的问题是:

  • 我是否错过了使第2点失效的东西?
  • 是否有更好的解决方法,可以使实现在技术上有效,同时又不必支持过多的额外代码。
  • 欢迎就此问题发表其他意见。

Vit*_*meo 11

提出建议std::get<>(std::tuple)以提供与相似的保证std::vector<>,并记录该代码仅在该标准尚未发布的版本中有效。

我认为这是要走的路,因为它为整个C ++社区提供了价值,不应成为实施者的负担。这也是您撰写第一个建议的绝好机会。

我建议您这样做,并且现在假设它可以正常工作,即使它是UB。如果您的软件是超关键的(例如飞行控制系统),并且您想100%确保您不依赖将来可能会破坏的功能,那么请实施自己的软件tuple

  • 注意,这应该扩展到标准库定义的get的其他用法。数组和对应该具有相同的保护。确实,可以说,如果一个类型是可分解的(可用于结构化绑定),那么当访问不同的索引时,调用的用户代码一定不会引起数据争用。 (6认同)