C++ multi-Ithread访问无序映射的运行时错误

C++ multi-Ithread访问无序映射的运行时错误,c++,multithreading,singleton,C++,Multithreading,Singleton,我有一段多线程代码,它试图使用stlunordered_map创建一个线程本地单例对象 这是你的电话号码。我在这里逐字复制代码: #include <iostream> #include <unordered_map> #include <vector> #include <thread> #include <algorithm> #include <mutex> using namespace std; class si

我有一段多线程代码,它试图使用stl
unordered_map
创建一个线程本地单例对象

这是你的电话号码。我在这里逐字复制代码:

#include <iostream>
#include <unordered_map>
#include <vector>
#include <thread>
#include <algorithm>
#include <mutex>
using namespace std;

class single
{
public:
    // Every thread needs to call this to get its individual instance
    static single* getInstance( unsigned int threadId );

    static void print( unsigned int threadId )
    {
        std::cout << "threadId:"    << threadId << ", Singleton: " << _instances[threadId] << std::endl;
    }

protected:
    // Made protected not private so that singleton can be subclassed
    single();                                           // Clients cant construct objects directly
    ~single();                                          // cannot be destroyed by clients

    single(const single &) = delete;                    // non-copyable
    single& operator=(const single &) = delete;         // can't be copy assigned
    single(single &&) = delete;                         // non-move constructible
    single & operator=(single && ) = delete;            // non-move assignable

private:
    static std::unordered_map<unsigned,single*> _instances;
    static std::mutex _lock;

};

std::mutex single::_lock;
std::unordered_map<unsigned,single*> single::_instances;

single::single(){}

single::~single(){}

single* single::getInstance( unsigned int threadId )
{
    if( _instances.count( threadId ) == 0 )
    {
        std::lock_guard<std::mutex> lg(_lock);
        if( _instances.count( threadId ) == 0 )
        {
            _instances[threadId] = new single;
            std::cout <<"Created By ThreadId: " << threadId <<std::endl;
        }
    }

    return _instances[threadId];
}

void Run( unsigned int threadId )
{
    single::getInstance(threadId)->print(threadId);
}

int main()
{
    std::vector<std::thread> workers;
    const unsigned threadCount = 16;

    for( auto i = 0; i != threadCount; ++i )
    {
        workers.push_back( std::thread( Run, i ) );
    }

    for_each( workers.begin(), workers.end(), std::mem_fn(&thread::join) );

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
单班
{
公众:
//每个线程都需要调用它来获取其单独的实例
静态单*getInstance(无符号int-threadId);
静态无效打印(无符号int-threadId)
{
标准::cout
有谁能解释一下,在这段代码的哪一部分发生了竞争情况

不,它不是线程安全的。一旦至少有一个写入程序,所有访问都需要由锁进行保护。因此,第一个
\u instances.count()
没有保护,可能会导致数据争用

…如果这个解决方案可以用于线程本地单例

您可以使用它来控制本地线程存储持续时间

您还可以在对
无序地图
进行任何访问之前,将锁防护装置迁移到

single* single::getInstance( unsigned int threadId )
{
    std::lock_guard<std::mutex> lg(_lock);
    if( _instances.count( threadId ) == 0 )
    {
        _instances[threadId] = new single;
        std::cout <<"Created By ThreadId: " << threadId <<std::endl;
    }
    return _instances[threadId];
}
single*single::getInstance(unsigned int-threadId)
{
标准:锁紧装置lg(锁紧装置);
if(_instances.count(threadId)==0)
{
_实例[threadId]=新的单个实例;

std::cout well,我提到了count()是一个常量函数。它不是线程安全的,因为它只读取并且不修改映射状态吗?
const
意味着
count()
函数不会更改容器的内容,并不意味着其他函数不会同时更改内容(数据竞争)。关于您的代码迁移建议,我最初是这样做的。但它不起作用。因此我认为我应该尝试使用双重检查锁定来防止_instances.count()上的争用条件所以,据我所知,基本上线程x使用计数读取和线程y写入容器之间存在竞争?是的,这是正确的。它在这里工作;您是否链接到pthread(不确定为什么它之前不工作)?