Home > Software engineering >  C 11 : Using local static variables in multithreaded program caused coredump
C 11 : Using local static variables in multithreaded program caused coredump

Time:12-28

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();
    }
}

CodePudding user response:

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.

  1. A program with a data race (undefined behavior) can produce any result.
  2. Yes, it can.

Consider the following instruction interleaving (time goes downwards):

  • T1 loads index into register (say 5).
  • T2 loads index (5 again)
  • T1 increments index to 6, stores "6" into its map
  • T1 loads 6, increments index to 7, stores "7" into its map
  • T2 "increments" index to 6, stores "6" into its own map
  • T1 loads 6, 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.

  • Related