在 lambda 中锁定 std::shared_ptr 的复制操作

Posted

技术标签:

【中文标题】在 lambda 中锁定 std::shared_ptr 的复制操作【英文标题】:Locking copy operation of std::shared_ptr inside lambda 【发布时间】:2020-01-21 17:49:20 【问题描述】:

对于这个示例代码:

#include <iostream>
#include <thread>
#include <mutex>
#include <memory>

struct A

    int _i;
    A(int i):_i(i)
    
        std::cout<<"A() "<<_i<<std::endl;
    
    ~A()
    
        std::cout<<"~A() "<<_i<<std::endl;
    
    void Print()
    
        std::cout<<"Print() "<<_i<<std::endl;
    
;

struct B

    std::shared_ptr<A> Asp;
    std::mutex AspMutex;

    void SetA()
    
        static int i = 0;
        std::unique_lock<std::mutex> lock(AspMutex);
        Asp = std::make_shared<A>(i);
    

    void AccessA1()
    
        std::shared_ptr<A> aspCopy;
        
            std::unique_lock<std::mutex> lock(AspMutex);
            aspCopy = Asp;
        
        (*aspCopy).Print();
    

    void AccessA2()
    
        auto aspCopy = [&]()
        
            std::unique_lock<std::mutex> lock(AspMutex);
            return Asp;
        ();
        (*aspCopy).Print();
    

    void AccessA3()
    
        (*[&]()
        
            std::unique_lock<std::mutex> lock(AspMutex);
            return Asp;
        ()
        ).Print();
    

;

int main()

    B b;
    b.SetA();
    std::thread t([&]b.SetA(););
    b.AccessA1();
    b.AccessA2();
    b.AccessA3();
    t.join();

我很好奇 c++17(或更高版本)标准是否会保证 A::Access1A::Access2 方法是线程安全的(std::shared_ptr 的副本将受 lock 保护)。

【问题讨论】:

你能解释一下目前线程不安全的地方吗?因为您似乎在锁后访问Asp 我不明白这个问题。你锁定,然后复制。为什么那不是线程安全的? 编辑:没关系,我在std::thread之前错过了b.SetA() @NicolBolas 据我所知没有。我只是好奇它是否会以任何方式危险。例如。 Access2 中的 Lambda 不能复制 shared_ptr 而是使用原始的等。 【参考方案1】:

是的。锁使A::Access1A::Access2 线程安全,并发SetA。在 C++17 中仍然如此。

【讨论】:

以上是关于在 lambda 中锁定 std::shared_ptr 的复制操作的主要内容,如果未能解决你的问题,请参考以下文章

SAL 注释:std::shared_ptr 的 _Ret_maybenull_

std::shared_mutex 是不是偏爱作者而不是读者?

这是 std::shared_ptr 的正确用法吗?

在 c++11 中转换 std::future 或 std::shared_future

为啥我不能在 C++0x 中对 std::shared_ptr 的向量执行 std::copy?

在 msvs 2013 中 std::shared_ptr 的 compare_exchange_weak 是不是损坏?