C++20中的std::jthread是什么?

37
  1. 它相对于std::thread有什么优势?
  2. 它会使现有的std::thread过时吗?

7
https://en.cppreference.com/w/cpp/thread/jthread - 463035818_is_not_a_number
2个回答

58

std::jthread 类似于 std::thread,但没有那个愚蠢的问题。看,std::thread 的析构函数会在你没有手动调用 joindetach 时终止程序。这导致了大量的bug,因为人们希望它在析构时自动加入线程。

jthread 解决了这个问题;默认情况下,它在析构时自动加入线程(因此命名为“joining thread”)。它还支持一种请求线程停止执行的机制,但没有强制要求这样做(也就是说:你不能强制让其他线程停止执行)。

目前,没有计划废弃std::thread


2
@Waqar:你可以这样看,但不一定是这样实现的。 - Nicol Bolas
2
我不禁想知道谁有如此亮丽的创意,试图榨入一个暂停执行功能。那从来没有成功过。在30年的线程中,任何地方都没有成功过。每个人都必须像以往一样使用自己显式的条件变量。 - Zan Lynx
4
确实有一个显式条件变量,它将其传递给运行的函数。 - Caleth
4
@Waqar,你需要将 std::stop_token 作为函数的第一个参数,并定期检查 stop_requested 是否为真。 - Caleth
1
@alexpanter 不,分离是另外一回事,嗯...分离。它只是意味着jthread在语义上等同于这个struct jthread : std::thread { using std::thread::thread; ~jthread() { join(); } };(故意省略了停止)。这意味着:a. 如果线程中的函数返回,线程的句柄可以直接析构;b. 如果没有返回,程序将阻塞并等待句柄(jthread对象)销毁时完成。在某些情况下,它可能表现得类似于分离,但绝不相同。 - alagner
显示剩余3条评论

-3
标准库提供了std::jthread,它是一个“加入线程”,通过其析构函数join()实现了RAII。加入操作是在析构函数中完成的,因此顺序与构造相反。 在使用std::jthread时要注意RAII语义。
int main() {

    long v {0};
    std::jthread t([&v]() {
        for (size_t i = 0; i++ < 10;)
            v++;
        });
        
    std::cout << v << ' '; // will print 0
}

这将在输出结果中打印0,因为拼接是在块的末尾完成的(即在std::cout << ...之后)。
int main() {

    long v {0};
        {
            std::jthread t([&v]() {
                for (size_t i = 0; i++ < 10;)
                    v++;

              std::cout << v << ' '; // will print 10
                });
        }
}

这将正确地打印10。
至于std::thread的弃用,我认为至少在不久的将来不会发生。


1
第一个示例打印0取决于操作系统的调度。在高负载系统中,第一个示例也可能打印10。您的示例不合适。 - walkerlala
这是一个数据竞争和未定义行为。任何阅读此文的人都不应该这样做。 - Passer By

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接