C++11:在多线程程序中使用局部静态变量导致核心转储

C++11 : Using local static variables in multithreaded program caused coredump

在C++11中,我创建了100个线程,每个线程调用Test::PushFunc,添加局部静态变量index ,插入到一个局部集合变量localMap.

理论上,index存储在初始化数据段内存中,由程序中的每个线程 运行 时间。 下一行

assert(it == localMap.end());

是合理的,因为index被插入到localMap 永不重复。

但实际上,程序是随机断言中的核心转储。你能告诉我为什么吗?谢谢

#include <set>
#include <iostream>
#include <thread>
class Test {
public:
    std::set<std::string> localMap;
    void PushFunc()
    {
        static uint64_t index = 0;
        while (true) {
            std::cout << "index : " << index << "\n";
            ++index;
            const auto& s = std::to_string(index);
            const auto& it = localMap.find(s);
            assert(it == localMap.end()); //! coredump here
            localMap.insert(s);
            if (index > 20000000) {
                break;
            }
        }
    }
};


int main ()
{
    std::vector<std::thread> processThreads;
    for (int i = 0; i < 100; ++i) {
        processThreads.emplace_back(
                std::thread([]()
                {
                    Test t;
                    t.PushFunc();
                }
                ));
    }
    for(auto& thread : processThreads){
        thread.join();
    }
}

But in practice, program is coredump in assert randomly. Can U tell me why ?

因为你有数据竞争——多个线程试图在没有任何同步的情况下读写同一个变量。

index 是一个 全局 变量。您需要使用互斥锁来保护对它的访问。

更新日期:

But localMap is not a global variable, data race cannot explain one index repeated twice.

  1. 具有数据竞争(未定义行为)的程序可以产生任何结果。
  2. 是的,可以。

考虑以下指令交错(时间向下):

  • T1 将 index 加载到寄存器中(比如 5)。
  • T2 加载 index(再次 5
  • T1 将 index 增加到 6,将 "6" 存储到它的映射
  • T1 加载 6,将 index 递增到 7,将 "7" 存储到其映射
  • T2 将索引“递增”到 6,将 "6" 存储到它自己的映射中
  • T1 加载 6,将其递增到 7,尝试将 "7" 存储到其映射中 ==> 断言失败!

问题是 index++ 不是 atomic 操作,并且(没有互斥锁)其他线程可能会干扰它。