You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程操作unordered_map时,未加读锁的find()是否安全?

多线程下std::unordered_map的find()方法线程安全性问题

问题背景

多线程操作std::unordered_map时,其find()方法是否安全?现有如下C++代码:

uint16_t GetLevel(const string& tag)
{
    static auto *tagMap = new std::unordered_map<std::string, int>();
    static shared_timed_mutex* mtx = new shared_timed_mutex;
    std::decay<decltype(*tagMap)>::type::iterator it;
    {
        //ReadLock lock(*mtx);
        it = tagMap->find(tag);
    }
    if (it == tagMap->end()) { // new tag
        InsertLock lock(*mtx);
        it = tagMap->find(tag); // secured for two thread went across above condition
        if (it == tagMap->end()) {
            auto result = tagMap->insert({ tag, 1 });
            if (!result.second) {
                return 0;
            }
            it = result.first;
        }
    }
    return it->second;
}

具体问题

若tagMap->find(tag)前未加readLock,当其他线程对tagMap执行insert(...)操作时,该find()调用是否安全?


回答

绝对不安全,原因如下:

  • C++标准明确规定,std::unordered_map不是线程安全容器。当存在线程执行写操作(比如insert、erase、触发rehash的操作)时,其他线程同时执行读操作(包括find)会触发数据竞争,属于未定义行为。
  • insert操作可能触发容器的rehash——此时哈希表的内部结构会被彻底重构,包括链表节点的重组、内存的重新分配。这时候正在执行find的线程可能访问到失效的指针/迭代器,读到错误数据,甚至直接导致程序崩溃。
  • 你代码里的“双重检查”逻辑不成立:第一次无锁find本身已经处于危险的竞争状态,就算后续加锁处理插入,也无法挽回前面无锁操作可能引发的未定义行为。

修正建议

  • 必须给所有读操作(包括第一次find)加上共享读锁(对应代码里的ReadLock,本质是std::shared_lock<std::shared_timed_mutex>)。这样多个读线程可以并行访问,写线程则需要等待所有读锁释放后才能获取独占锁执行insert,严格保证读写互斥。
  • 保留第二次加锁后的find检查是必要的,这是为了处理多个线程同时通过第一次无锁find(未找到)的情况,避免重复插入相同元素。

内容的提问来源于stack exchange,提问作者bu haha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:03:12