Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用std::jthread安全地注册std::stop_回调_C++_Multithreading_C++20 - Fatal编程技术网

C++ 如何使用std::jthread安全地注册std::stop_回调

C++ 如何使用std::jthread安全地注册std::stop_回调,c++,multithreading,c++20,C++,Multithreading,C++20,对于如何安全地为jthread注册回调,我有点困惑。您需要标记,这意味着您需要在创建jthread之后进行注册,这意味着回调将在jthread之前被销毁。在下面的示例中,cb5和cb6显然会在jthread的dtor启动之前被销毁,因此它们会自动取消注册,并且永远不会执行。相反地,cb1和cb2在jthread销毁后被显式销毁,因此它们保证作为请求停止的数据的副作用执行。现在令人困惑的是,我找不到任何保证cb3和cb4能够保证执行的保证。我找不到任何东西表明请求stop会自动更改设置stop标志

对于如何安全地为
jthread
注册回调,我有点困惑。您需要
标记
,这意味着您需要在创建
jthread
之后进行注册,这意味着回调将在
jthread
之前被销毁。在下面的示例中,
cb5
cb6
显然会在
jthread
的dtor启动之前被销毁,因此它们会自动取消注册,并且永远不会执行。相反地,
cb1
cb2
jthread
销毁后被显式销毁,因此它们保证作为请求停止的数据的副作用执行。现在令人困惑的是,我找不到任何保证
cb3
cb4
能够保证执行的保证。我找不到任何东西表明请求stop会自动更改设置stop标志并执行所有回调。另一方面,我查看了
request\u stop
的函数,它似乎执行以下操作

  • 带锁
  • 设置停止标志并获取上次注册的停止回调
  • 松开锁
  • 运行回调
  • 释放二进制信号量(该回调的析构函数等待该信号量)
  • 尝试重新获取锁以执行下一个回调
现在,最后一个问题是,根据上面的说明,
cb3
cb4
的执行正在与其析构函数竞争(至少是
cb3
,因为
cb4
将被选择在用于设置停止标志的同一个锁下执行,但我同样找不到此处提到的
cb4
的保证).那么,如果不显式调用
request\u stop
,如何在
jthread
中正确使用
stop\u回调
?您不能在之后注册回调,因为它们会在之前被销毁,比如
cb5
cb6
,您也不能在线程中注册它们,因为它们不能保证执行e就像
cb3
cb4
一样,我不认为这是为了让它们以
cb1
cb2
的复杂方式延长寿命

#include <chrono>
#include <iostream>
#include <stop_token>
#include <thread>

int main(int argc, const char * const * const argv)
{
    using namespace std::chrono_literals;

    const auto _cb1 = []() -> void {
        std::cout << "cb1\n";
        std::this_thread::yield();
        std::this_thread::sleep_for(10s);
    };

    const auto _cb2 = []() -> void {
        std::cout << "cb2\n";
        std::this_thread::yield();
        std::this_thread::sleep_for(10s);
    };

    using CB1 =
        decltype(std::stop_callback(std::declval<std::stop_token>(), _cb1));
    using CB2 =
        decltype(std::stop_callback(std::declval<std::stop_token>(), _cb2));

    std::byte storage1[sizeof(CB1)];
    std::byte storage2[sizeof(CB2)];

    const CB1 * cb1 = nullptr;
    const CB2 * cb2 = nullptr;

    {

        std::jthread worker([](const std::stop_token & stop_token) {
            std::stop_callback cb3(stop_token, [] {
                std::cout << "cb3\n";
                std::this_thread::yield();
                std::this_thread::sleep_for(10s);
            });
            std::stop_callback cb4(stop_token, [] {
                std::cout << "cb4\n";
                std::this_thread::yield();
                std::this_thread::sleep_for(10s);
            });

            while (!stop_token.stop_requested())
            {
            }
        });


        cb1 = new (&storage1) std::stop_callback(worker.get_stop_token(), _cb1);

        cb2 = new (&storage2) std::stop_callback(worker.get_stop_token(), _cb2);


        std::stop_callback cb5(worker.get_stop_token(), [] {
            std::cout << "cb5\n";
            std::this_thread::yield();
            std::this_thread::sleep_for(10s);
        });

        std::stop_callback cb6(worker.get_stop_token(), [] {
            std::cout << "cb6\n";
            std::this_thread::yield();
            std::this_thread::sleep_for(10s);
        });

        std::this_thread::sleep_for(2s);
    }

    cb1->~CB1();
    cb2->~CB2();

    return 0;
}
#包括
#包括
#包括
#包括
int main(int argc,const char*const*const argv)
{
使用名称空间std::chrono_文本;
const auto_cb1=[]()->void{
std::cout void{
标准::cout标准:

对返回true的
请求停止
的调用与对返回true的相关
停止令牌
停止源
对象的
请求停止
的调用同步

这意味着对所请求的
stop\u
的调用会在之后返回
true
任何返回
true
request\u stop
。因此,在调用
request\u stop
实际将
true
返回到某个线程之前,您的
while
循环无法退出。更重要的是,在此类调用返回之前,它无法退出

请求停止
是为了:

如果发出请求,则同步调用关联的
stop\u callback
对象注册的回调

被“同步地”调用意味着:这个函数要么在请求停止的线程上调用它们,要么与它们被调用的任何线程同步。主要的一点是,在这些回调完成之前,这个函数不会返回

在该函数返回之前,
stop\u requested
将不会返回
true
,如前所述


因此不存在数据竞争。在线程退出之前,回调不会被销毁。

“我找不到任何东西表明请求停止会自动更改设置停止标志并执行所有回调,例如。”嗯,你看了哪里?可能我不够清楚。它到底说它在哪里以原子方式设置标志并在同一个原子操作中执行所有回调?如果它说“以原子方式”又有什么关系或者不是;它与请求的
stop\u
调用同步。它说这样的调用不会引入数据竞争。谢谢你的澄清。听起来很有说服力,我只是试图用代码来理解它,但仍然不能完全理解它。所以在第264行和第270行之间,锁被释放,而解构函数被释放当前回调被信号量解除阻塞,因此下一个回调的析构函数能否快速获取锁并注销自身并完成销毁过程?停止请求位设置在232中,检查停止请求函数的线程是否无法直接观察到?我的意思是,此函数所做的一切只是检查此位是否为s