在多线程代码中使用shared_ptr

问题描述:

有一个示例代码在多线程环境中“工作”:在多线程代码中使用shared_ptr

void CSampleClass::Stop(void) { 
    if (m_pDB != nullptr) { 
    ... Here is some code 
    m_pDB->Interrupt(); 
    } 
}
,其中 m_pDB成员声明为 boost::shared_ptr<CSampleDatabase> m_pDB;m_pDB可以在另一个类的方法中重置。这就是为什么它被测试不是 nullptr。由于代码具有多个线程,因此被另一个线程重置,在 if (...)m_pDB->Interrupt();之间时,可以是 情况。结果是相当戏剧性的。为了防止出现这种情况,我使用以下代码修改
void CSampleClass::Stop(void) { 
    auto pDb = m_pDB; //lock 
    if (pDb != nullptr) { 
    ... Here is some code 
    pDb->Interrupt(); 
    } 
}
,即如果调用了 m_pDB.reset();,则在销毁 pDb之前,对象永远不会被释放。

的问题是:

  1. 是否有一个“标准”的方式,以防止情况不涉及储物柜,互斥,临界区等?像使用boost::weak_ptr来打破循环引用。

  2. 确保编译器声明pDBboost::shared_ptr<CSampleDatabase>而不是CSampleDatabase *?可能是写decltype(m_pDB) pDb = m_pDB; //lock更安全吗?

+2

第二个版本仍然包含竞争条件。复制构建'shared_ptr'不是一个原子操作。 – Mankarse 2012-03-24 08:28:22

+0

@Mancarse:引用? – 2012-03-24 08:49:54

+0

@nm:从[here](http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#ThreadSafety):“shared_ptr对象提供与内置相同级别的线程安全性类型”。这意味着多个'shared_ptr'实例引用同一对象并同时修改这些'shared_ptr'是安全的,但同时修改/读取一个'shared_ptr'实例并不安全。 – Mankarse 2012-03-24 09:05:59

提供的解决方案并不安全。它类似于这个例子从the documentation

// thread A 
p = p3; // reads p3, writes p 

// thread B 
p3.reset(); // writes p3; undefined, simultaneous read/write 

同时来自同一个实例读取是安全的。在同一个实例上的任何其他并发操作都不是。

有没有一种“标准”方式来防止不涉及储物柜,互斥体,临界区等情况?就像使用boost :: weak_ptr来打破循环引用一样。

您需要互斥,所以您需要使用互斥构造。

能够保证所有的编译器声明pDBboost::shared_ptr<CSampleDatabase>,而不是CSampleDatabase *?可能是写decltype(m_pDB) pDb = m_pDB; //lock更安全吗?

是的,pDB将是shared_ptr