首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >thread_guard对scoped_thread

thread_guard对scoped_thread
EN

Stack Overflow用户
提问于 2019-06-07 15:31:55
回答 2查看 1K关注 0票数 7

在书中

安东尼·威廉姆斯的"C++并发在行动中“

您可以找到以下两个代码片段(我已经介绍了一些轻微的修改):

片段1:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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的优势在哪里?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-07 19:51:03

这两种类型都是在销毁时阻塞(例如范围退出),直到线程完成为止。区别在于thread对象的所有权。

thread_guard本身并不拥有thread;在同一个thread上可能有多个thread_guard在等待。这也意味着只要任何thread引用它,thread_guard对象都必须是活动的。如果当thread_guard对象被破坏时,引用的线程已经被连接,那么它不会阻止或产生错误(而不仅仅是在不可连接的线程上调用join )。

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

最终,您使用的是语义问题:您希望等待其他人拥有的线程(然后还必须确保没有生命周期问题),还是希望thread对象在被销毁时阻塞,而不必先对其进行join

票数 5
EN

Stack Overflow用户

发布于 2019-06-07 18:07:04

就功能而言,这两种实现都能够为目的服务,我在这两种实现中唯一能看到的区别是,Snippet 2可以同时接受lvalue(glvalue)rvalue(prvalue),但Snippet 1不能接受rvalue(prvalue)作为构造函数参数。例如,考虑下面的代码,

代码语言:javascript
复制
std::thread getThread()
{
    return std::thread([](){ std::cout<< __PRETTY_FUNCTION__<< std::endl;});
}

int main( int , char *[])
{
    thread_guard g( getThread());
    return 0;
}

现在,如果编译这段代码,编译将给出以下错误,

代码语言:javascript
复制
 error: cannot bind non-const lvalue reference of type ‘std::thread&’ to an rvalue of type ‘std::remove_reference<std::thread&>::type’ {aka ‘std::thread’}
     explicit thread_guard(std::thread _t): t(std::move( _t)){ std::cout<< __PRETTY_FUNCTION__<< std::endl;}

但是snippet 2实现将很好地工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56497350

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档