c++ - 这种编码线程安全,死锁安全吗?

标签 c++ boost thread-safety

下面我们有数据容器。我们希望多个线程能够搜索 Container 并获取 Data 对象。

#include <boost/thread.hpp>

using boost::shared_ptr;
using  boost::mutex;
using  boost::lock_guard;
using std::string;

class CData
{
public:
    bool find(string& value, const string& fieldName)
    {
        lock_guard<mutex> guard(m_lock);
        auto it=m_data.find(fieldName);
        if( it!=m_data.end())
        {
            value=it->second;
            return true;
        }
        return false;
    }


    CData(const CData& rhs)
    {
        lock_guard<mutex> guard(rhs.m_lock);
        m_data=rhs.m_data;
    }

    CData& operator=( const CData& rhs ) 
    {
       if ( this == &rhs ) 
       {
           return *this; 
       }

       mutex* lock1;
       mutex* lock2;

       if(this<&rhs)
       {
           lock1=&m_lock;
           lock2=&rhs.m_lock;
       }
       else
       {
           lock1=&rhs.m_lock;
           lock2=&m_lock;
       }

       lock_guard<mutex> guard1(*lock1);
       lock_guard<mutex> guard2(*lock2);

       m_data=rhs.m_data;
    }



private:

    std::map<string,string> m_data;
    mutable mutex m_lock;
};

容器在 map 中保存共享点。不同的线程将查找容器中的对象并查找对象中的字段。

class CDataContainer
{
public:
    CDataContainer* instance()
    {
        static CDataContainer* s_instance;
        static mutex s_instanceLock;
        lock_guard<mutex> guard(s_instanceLock);
        if(!s_instance)
        {
            s_instance=new CDataContainer;
        }
        return s_instance;
    }

    void insert(const string& key, const shared_ptr<CData>& data)
    {
        lock_guard<mutex> guard(m_lock);
        m_key2data[key]=data;
    }


    void erase(const string& key)
    {
        lock_guard<mutex> guard(m_lock);
        m_key2data.erase(key);
    }

    bool find(shared_ptr<CData>& data,const string& key)
    {
        lock_guard<mutex> guard(m_lock);
        auto it=m_key2data.find(key);
        if( it!=m_key2data.end())
        {
            data=it->second;
            return true;
        }
        return false;
    }



private:
    CDataContainer()

    }

    mutex m_lock;
    std::map<string,shared_ptr<CData>> m_key2data;
};

最佳答案

也许吧,虽然到处都是互斥体,但效率可能不高。如果我可以建议一个小的修改:

class CData
{
public:
    void insert(const string& key, const shared_ptr<CData>& data) const;
    ...
private:
    const std::map<string,string> m_data;
};

现在您不需要 CData 中的任何互斥体,并且您可以更加确信它的线程安全性。多线程真正的前进方向是从常量的角度来考虑它。我建议阅读 Bartosz's blog他在其中展示了如何仅通过使用不变性来编写没有互斥锁或同步的线程安全 C++。

编辑:作为附加说明,在没有死锁的情况下获取多个互斥锁的正确方法是使用 std::lock ,如:

    std::unique_lock<std::mutex> lk1(m_lock, std::defer_lock);
    std::unique_lock<std::mutex> lk2(rhs.m_lock, std::defer_lock);
    std::lock(lk1, lk2);

Edit2: CDataContainer::instance 中的同步在 C++11 中也是不必要的现在可以完全安全地执行以下操作:

CDataContainer& instance()
{
    static CDataContainer s_instance;
    return s_instance;
}

关于c++ - 这种编码线程安全,死锁安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26196066/

相关文章:

java - 对于写入固定大小数组的不同部分的并行线程,是否存在线程安全的 Java 数据结构?

c++ - 线程什么时候退出?

c++ - 在 C/C++ 中乘以小数(相对于高数)是否更快?

c++ - 如何安全地使用 QQmlEngine::CppOwnership?

c++ - 全局 Shell Hook 只注册本地事件

c++ - 如何将函数值更改为 C++ 中表( Gamma 分布)中的值?

c++ - 使用 Boost 时的内存泄漏检测

c++ - 如何更改 dynamic_bitset 的值?

c++ - 使用 boost 线程库打印

c++ - boost BGL 线程安全