在书里



您可以找到以下两个代码段(我进行了一些细微的修改):

片段1:

class thread_guard
{
    std::thread& t;
    public:
    explicit thread_guard(std::thread& t_): t(t_){}
    ~thread_guard()
    {
        if(t.joinable())
    {
        t.join();
    }
    }
    thread_guard(thread_guard const&)=delete;
    thread_guard& operator=(thread_guard const&)=delete;
};

void my_func()
{
    for(int j = 0; j < 1000; ++j)
    {
        cout << "\n " << j;
    }
}

void f()
{
    std::thread t1(my_func);
    thread_guard g(t1);
    do_something_in_current_thread();
}

int main()
{
    f();
    return 0;
}

继续你可以找到

片段2:
class scoped_thread
{
    std::thread t;
    public:
    explicit scoped_thread(std::thread t_):    t(std::move(t_))
    {
        if(!t.joinable())
        throw std::logic_error(“No thread”);
    }
    ~scoped_thread()
    {
        t.join();
    }
    scoped_thread(scoped_thread const&)=delete;
    scoped_thread& operator=(scoped_thread const&)=delete;
};

void my_func()
{
    for(int j = 0; j < 1000; ++j)
    {
        cout << "\n " << j;
    }
}

void f()
{
   scoped_thread st1(thread(my_func));

   thread t2(my_func);
   scoped_thread st2(move(t2));

   do_something_in_current_thread();
}

int main()
{
    f();
    return 0;
}

我不确定我是否真的能体会到这两个摘要之间的真正区别。

我可以看到的唯一区别是,在代码片段1中,thread_guard实例不拥有线程t1的所有权(与scoped_thread对象不同),因此可以调用t1.join(),但这在执行~thread_guard()时不成问题。

那么:摘录2的优势在哪里(如果存在)?

最佳答案

这两种类型都将在破坏(例如作用域退出)时阻塞,直到线程完成为止。不同之处在于thread对象的所有权。
thread_guard本身不拥有thread;在同一个thread_guard上可能有不止一个thread在等待。这也意味着,只要任何thread引用了thread_guard对象,该对象都必须处于 Activity 状态。如果销毁了thread_guard对象时已引用的线程已经加入,则不会阻塞或产生错误(与仅在不可连接的线程上调用join相对)。

另一方面,scoped_thread拥有thread实例的所有权,因此也控制了它的生存期。每当您想拥有自己要等待的线程时,例如,当您拥有该线程时,就可以使用它。作为数据成员。

最终,您使用的是一个语义问题:您要等待别人拥有的线程(然后还必须确保不存在生命周期问题),还是想要thread对象在获取时阻塞?已销毁,无需先对其进行join编码。

关于c++ - thread_guard与scoped_thread,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56497350/

10-10 06:45