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.
- 具有数据竞争(未定义行为)的程序可以产生任何结果。
- 是的,可以。
考虑以下指令交错(时间向下):
- T1 将
index
加载到寄存器中(比如 5
)。
- T2 加载
index
(再次 5
)
- T1 将
index
增加到 6
,将 "6"
存储到它的映射 中
- T1 加载
6
,将 index
递增到 7
,将 "7"
存储到其映射
- T2 将索引“递增”到
6
,将 "6"
存储到它自己的映射中
- T1 加载
6
,将其递增到 7
,尝试将 "7"
存储到其映射中 ==> 断言失败!
问题是 index++
不是 atomic 操作,并且(没有互斥锁)其他线程可能会干扰它。
在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.
- 具有数据竞争(未定义行为)的程序可以产生任何结果。
- 是的,可以。
考虑以下指令交错(时间向下):
- T1 将
index
加载到寄存器中(比如5
)。 - T2 加载
index
(再次5
) - T1 将
index
增加到6
,将"6"
存储到它的映射 中
- T1 加载
6
,将index
递增到7
,将"7"
存储到其映射 - T2 将索引“递增”到
6
,将"6"
存储到它自己的映射中 - T1 加载
6
,将其递增到7
,尝试将"7"
存储到其映射中 ==> 断言失败!
问题是 index++
不是 atomic 操作,并且(没有互斥锁)其他线程可能会干扰它。