程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何使用 std::jthread大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决如何使用 std::jthread?

开发过程中遇到如何使用 std::jthread的问题如何解决?下面主要结合日常开发的经验,给出你关于如何使用 std::jthread的解决方法建议,希望对你解决如何使用 std::jthread有所启发或帮助;

我对如何安全地为 jthread 注册回调有点困惑。您需要 token,这意味着您需要在创建 jthread 之后进行注册,这意味着回调将在 jthread 之前销毁。在下面的示例中,cb5cb6 显然在 jthread 的 dtor 启动之前被销毁,因此它们会自动注销自己并且永远不会执行。相反,cb1cb2 在销毁 jthread 后被显式销毁,因此它们可以保证作为请求停止的 dtor 的副作用执行。现在令人困惑的部分是我找不到任何保证 cb3cb4 保证执行的保证。例如,我找不到任何内容表明请求停止会自动更改设置停止标志并执行所有回调。另一方面,我查看了 request_stop 的 Implementation:223,它似乎执行以下操作@H_403_27@

  • 需要一个锁
  • 设置停止标志并获取最后注册的停止回调
  • 解除锁定
  • 运行回调
  • 释放二进制信号量(回调的析构函数等待)
  • 尝试重新获取锁以执行下一个回调

现在终于到问题了,根据上述,cb3cb4 的执行正在与它们的析构函数竞争(至少 cb3,因为 cb4 将是选择在将用于设置停止标志的同一锁下执行,但我再次找不到对某处提到的 cb4 的保证)。那么如何在不显式调用 stop_callBACk 的情况下正确地将 jthreadrequest_stop 一起使用?您不能在之后注册回调,因为它们会在 cb5cb6 之前被销毁,并且您不能在线程中注册它们,因为它们不能保证像 cb3cb4 并且我不认为这是为了以cb1cb2@H_403_27@ 的复杂方式延长它们的使用寿命

#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;
}
@H_301_75@ 

解决方法

标准directly states that:

返回 true 的对 request_­stop 的调用与返回 true 的关联 stop_requestedstop_­token 对象上的 stop_­source 调用同步。

这意味着对返回 stop_requestedtrue 的调用“发生在”任何返回 request_stoptrue 之后。因此,您的 while 循环无法退出,直到对 request_stop 的调用实际将 true 返回给某个线程。更重要的是,它不能退出,直到这样的调用返回

request_stop 是 explicitly stated 到:

如果发出请求,则同步调用关联 stop_callBACk 对象注册的回调。

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

并且在此函数返回之前,stop_requested 不会返回 true,如前所述。

所以没有数据竞争。线程退出前回调不会被销毁。

大佬总结

以上是大佬教程为你收集整理的如何使用 std::jthread全部内容,希望文章能够帮你解决如何使用 std::jthread所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。