Home > Blockchain >  why is there a race condition in this multithreading snippet
why is there a race condition in this multithreading snippet

Time:12-08

I have this code in c using multithreading but I am unsure why I am getting the output I am getting.

void Fun(int* var) {
    int myID;
    myID = *var;
    std::cout << "Thread ID: " << myID << std::endl;

}

int main()
{
    using ThreadVector = std::vector<std::thread>;
    ThreadVector tv;
    std::cout << std::thread::hardware_concurrency() << std::endl;
    for (int i = 0; i < 3  ;   i)
    {
        auto th = std::thread(&Fun, &i);
        tv.push_back(std::move(th));
    }
    for (auto& elem : tv)
    {
        elem.join();
    }

}

I am wondering if there is a race condition for the i variable, and if so, how does it interleave? I tried to compile it and I constantly got the Thread ID printout as 3, but I was surprised because I thought the variable had to be global in order to be accessed by the various new threads?

This is what I thought would happen: thread 1 is created, Fun starts to run in thread 1 with myid = 0, main thread continues running and increments i, 2nd thread is created and the myid for that would be myid=1... and so on. And so the printout would be the myID in increments i/e 1,2,3

I know that I can solve this with std::lock_guard but I am just wondering how is the interleaving (LOAD, INCREMENT,STORE) happening that causes this race condition for the i variable.

Kind help is appreciated thank you!

CodePudding user response:

I am wondering if there is a race condition for the i variable

Yes, most definitely. The parent thread writes to i, which is a non-atomic variable, and the child threads read it, without any intervening synchronization. That's the exact definition of a data race in C .

and if so, how does it interleave?

Data races in C cause undefined behavior, and any behavior you may observe does not have to be explainable by interleaving.

I tried to compile it and I constantly got the Thread ID printout as 3, but I was surprised because I thought the variable had to be global in order to be accessed by the various new threads?

No, it doesn't have to be global. Threads can access variables which are local to other threads if they are somehow passed a pointer or reference to such a variable.

This is what I thought would happen: thread 1 is created, Fun starts to run in thread 1 with myid = 0, main thread continues running and increments i, 2nd thread is created and the myid for that would be myid=1... and so on. And so the printout would be the myID in increments i/e 1,2,3

Well, nothing at all in your program forces those events to occur (or become observable) in that order, so there is really no basis for expecting that they will. It's entirely possible, for instance, that the three threads all get started, but don't get a chance to actually run until after the loop in main has completed, at which point i has the value 3. (Or rather, the memory where i used to be located, as it is now out of scope and its lifetime has ended - it's a separate bug that you don't prevent that from happening.)

CodePudding user response:

This is the version of the code that would not exhibit a data race:

#include <iostream>
#include <thread>
#include <vector>

// since `id` is passed by value, each thread will work on its own copy and no
// data race is possible
void fun(int id) { std::cout << "thread id: " << id << "\n"; }

int main() {
  std::vector<std::thread> threads;

  for (auto id = 0; id < 3;   id) {
    threads.emplace_back(fun, id);
  }

  for (auto& thread : threads) {
    thread.join();
  }
}

Since each thread receives a copy of the variable id, there is no race (except for the scrambled output due to unsynchronized std::cout, but I assume that's not part of this discussion).

Variables do not need to be global for their use in multiple threads. In fact, global variables often make it more difficult or even practically impossible to write multithreaded code, since there is no guarantee that every read and write will be appropriately synchronized.

  • Related