【问题标题】:thread::detach during concurrent thread::join in C++线程::分离期间并发线程::加入C++
【发布时间】:2022-10-23 21:14:56
【问题描述】:

在下面的程序中,一个线程(main)正在执行thread::join,另一个线程(x)调用thread::detach

#include <thread>
#include <iostream>

int main(void) {
    auto t = std::thread([] {
        std::this_thread::sleep_for( std::chrono::milliseconds(1000) );
    } );
    auto x = std::thread([&t] {
        std::this_thread::sleep_for( std::chrono::milliseconds(500) );
        if ( t.joinable() )
        {
            std::cout << "detaching t..." << std::endl;
            t.detach();
        }
    } );
    std::cout << "joining t..." << std::endl;
    t.join();
    x.join();
    std::cout << "Ok" << std::endl;
    return 0;
}

它在 GCC 的 libstdc++ 和 Clang 的 libc++ 打印中工作正常

joining t...
detaching t...
Ok

但在 Visual Studio 中,程序在打印 Ok 之前以非零退出代码终止。在线演示:https://gcc.godbolt.org/z/v1nEfaP7a

它是 Visual Studio 中的错误还是程序包含一些未定义的行为?

【问题讨论】:

  • std::thread 对象本身不是线程安全的。从两个线程对它调用joinjoinable 同时通过数据竞争表现出未定义的行为。
  • 这与例如有什么不同?一个线程推送到一个向量和另一个弹出?
  • 当另一个线程调用detach 函数时,一个线程耐心地等待thread 通告它所代表的线程已经完成,因此thread 不再代表一个线程。你可以很容易地得到另一个明显的结果,线程在连接之前就被分离了。或者你可以让线程被分离尽管它正在加入。这三种情况都令人不快。不要这样做。

标签: c++ multithreading language-lawyer


【解决方案1】:

joindetach 都不是 const 限定的,因此允许实现修改 thread 对象的内部存储器,而不必提供任何保证写入/写入或写入/读取数据竞争避免非同步调用根据 [res.on.data.races] 的默认数据竞争避免要求,这些成员函数。

在 [thread.threads] 或其他任何地方提到的这些功能的这条规则也没有例外。

因此调用joindetach 而不在两个调用之间建立happens-before 关系是数据竞争并导致未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 2013-08-28
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    相关资源
    最近更新 更多