【问题标题】:Different behaviour while passing shared_ptr to weak_ptr in thread functions and normal functions在线程函数和普通函数中将 shared_ptr 传递给 weak_ptr 时的不同行为
【发布时间】:2018-09-08 14:52:53
【问题描述】:

我有一个线程函数,它需要一个weak_ptr,我在线程函数中传递了我的shared_ptr。

从法律上讲,weak_ptr 不应增加 shared_ptr 的引用计数,但是,除非我在将其传递给线程函数时使用 weak_ptr 进行类型转换,否则它会增加引用计数(意外)

这种行为只发生在线程函数中,而不是普通函数调用。

这是线程函数的代码

void thrdfn(weak_ptr<int> wp) {
    cout<<wp.use_count()<<endl;  // Prints 2
}

int main() {
    shared_ptr<int> sp = make_shared<int>();
    thread th { thrdfn, (sp)};
    th.join();
    return 0;
}

但是,当我在创建线程时进行类型转换时,它的行为正常

void thrdfn(weak_ptr<int> wp) {
    cout<<wp.use_count()<<endl;  // Prints 1
}

int main() {
    thread th { thrdfn, weak_ptr<int>(sp)}; // typecast 
}

当我将函数作为普通函数调用时,它可以正常工作而无需类型转换

void thrdfn(weak_ptr<int> wp) {
    cout<<wp.use_count()<<endl;  // Prints 1
}

int main() {
    shared_ptr<int> sp = make_shared<int>();
    thrdfn(sp);
    return 0;
}

多个编译器的行为相同

【问题讨论】:

    标签: c++ multithreading c++11 c++14 smart-pointers


    【解决方案1】:

    当你编写一个std::thread 时(我删除了多余的括号):

    thread th{thrdfn, sp};
    

    会发生什么:

    新的执行线程开始执行

    std::invoke(decay_copy(std::forward<Function>(f)), decay_copy(std::forward<Args>(args))...);
    

    decay_copy 被定义为

    template <class T>
    std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }
    

    也就是说,您的shared_ptr 被复制到线程中,您从该副本中取出weak_ptr。所以有两个shared_ptrs:你的和thread的。

    【讨论】:

    • 在线程的生命周期内计数保持为 2,不管需要多长时间。
    • @DakshGupta 抱歉,我没有想清楚。
    【解决方案2】:

    避免尝试从 shared_ptr 到 weak_ptr 的自动转换,它可能会创建额外的 shared_ptr。以下 sn-p 应该可以正常工作:

    shared_ptr<int> sp = make_shared<int>();
    weak_ptr<int> weak = sp;
    thread th { thrdfn, (weak)};
    

    【讨论】:

    • 关于为什么复制,见here线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如,使用 std::ref 或 std::cref)。
    • 感谢您的回答,但代码与类型转换没有什么不同。我的问题是想知道为什么会发生这种情况,是否有任何规范要求行为差异
    • "但代码与类型转换没有什么不同"> 两者都您正在做的或 seccpur 建议的类型转换。
    猜你喜欢
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 2012-08-13
    • 2022-08-05
    • 2015-08-31
    • 2022-01-12
    • 2012-09-27
    • 1970-01-01
    相关资源
    最近更新 更多