【问题标题】:How do I put a thread in a C++ smart pointer?如何将线程放入 C++ 智能指针中?
【发布时间】:2016-06-05 20:01:18
【问题描述】:

我想创建一个 C++ 类,其中一个线程每分钟做一次工作。

首先,我可以将线程定义为变量成员吗?

class my_class
{
public:
    my_class()
        : my_thread_(task, this)
    {
    }

    ~my_class()
    {
        done_ = true;
    }

    void run()
    {
        while(!done_)
        {
            ...do work in the thread...
        }
    }

private:
    static task(my_class * ptr)
    {
        ptr->run();
    }

    std::thread          my_thread_;
    std::atomic<bool>    done_ = false;
};

其次,我可以使用带有线程的智能指针吗?

class my_class
{
public:
    ~my_class()
    {
        done_ = true;
    }

    void init()
    {
        my_thread_.reset(new std::thread(task, this));
    }

    void run()
    {
        while(!done_)
        {
            ...do work in the thread...
        }
    }

private:
    static task(my_class * ptr)
    {
        ptr->run();
    }

    std::unique_ptr<std::thread>    my_thread_;
    std::atomic<bool>               done_ = false;
};

在我看来,我需要在子线程被销毁之前加入它,但我想知道 std::thread 的析构函数是否知道安全地这样做。

【问题讨论】:

    标签: c++ multithreading c++14


    【解决方案1】:

    您可以将std::threads 放在任何您想要的位置,它们并不特别。销毁线程句柄是有问题的。您可以隐式分离、隐式杀死或隐式加入,每个选项都是错误的。 std::~thread(通常)just kills the whole program。为了防止joindetach 它。
    由于您似乎想要隐式加入,您可能需要使用std::async(可能与std::launch::async policy)来启动您的线程。它返回一个std::future,其析构函数隐式加入。

    【讨论】:

    • 只有我希望我的进程始终在后台运行,而 std::async,据我了解,不能 100% 保证创建一个运行任务的 trhead。它可以在前面的线程中完成。但我确实需要将并行运行的任务分开。
    • @AlexisWilke 这就是为什么我评论了std::launch::async 政策,它强制std::async 创建一个线程。如果您不关心同步,只想运行一个线程,请使用 std::thread 并在其上调用 .detach()
    【解决方案2】:

    可以创建std::unique_ptr&lt;std::thread&gt;。当 unique_ptr 的作用域结束时,它将调用 std::thread 析构函数。请记住,调用 std::thread 析构函数并不是轻轻地终止线程运行,而是通过std::terminate 终止。要正常结束 std::thread,您必须在 std::thread 对象上运行.join()

    【讨论】:

      【解决方案3】:

      根据cppreference.com

      线程对象没有关联的线程(并且对 销毁)之后

      • 它是默认构造的
      • 它被移出
      • join() 已被调用
      • detach() 已被调用

      因此,如果您将线程定义为成员变量并像这样编写您的析构函数:

      ~my_class()
      {
          done_ = true;
          my_thread_.join();
      }
      

      一切都很好,因为标准保证std::thread析构函数只会在my_class析构函数see this Q/A之后被调用。

      【讨论】:

      • 我实际上错过了参考中的那个列表......这也意味着 std::thread 不是异常安全的!
      猜你喜欢
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      • 2019-09-21
      相关资源
      最近更新 更多