In C++11, I create 100 threads, every thread call Test::PushFunc, add local static variable index, insert to a local set variable localMap.
In theory, index is stored in Initialized Data Segment Memory and was added by every thread in program running time. Following line
assert(it == localMap.end());
is reasonable because of index to be inserted into localMap is never repeated.
But in practice, program is coredump in assert randomly. Can U tell me why ? Thanks.
#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 ?
Because you have a data race -- multiple threads are trying to read and write the same variable without any synchronization.
The index
is a global variable. You need to guard access to it with a mutex.
Udate:
But localMap is not a global variable, data race cannot explain one index repeated twice.
Consider the following instruction interleaving (time goes downwards):
index
into register (say 5
).index
(5
again)index
to 6
, stores "6"
into its map6
, increments index
to 7
, stores "7"
into its map6
, stores "6"
into its own map6
, increments it to 7
, tries to store "7"
into its map ==> assertion failure!The issue is that index++
is not an atomic operation, and (without mutex) other threads may interfere with it.