Data Races

  • A "data race" occurs when:

    • Two or more threads access the same memory location
    • And at least one of the threads modifies it
    • And the threads are not synchronized when they access the memory location
  • Only safe if the threads are synchronized

    • One thread accesses the memory location at a time
    • The other threads have to wait until it is safe for them to access it
    • In effect, the threads execute sequentially while they access it
  • A data race causes undefined behavior

    • The program is not guaranteed to behave constantly

// unsynchronized threads which make conflicting accesses
// But where is the shared memory location?

#include <iostream>
#include <string>
#include <thread>

void print(std::string str) {
  for (int i = 0; i < 5; ++i) {
    std::cout << str[0] << str[1] << str[2] << std::endl;
  }
}

int main() {
  std::thread thr1(print, "abc");
  std::thread thr2(print, "def");
  std::thread thr3(print, "xyz");

  thr1.join();
  thr2.join();
  thr3.join();
}

Output

  • The output will be scrambled up
  • What has gone wrong?
    • Threads can be interrupted during output
    • Other threads can run and write their output
    • The output from different threads is interleaved

Data Race Consequences

  • In this program, the data race caused interleaved output

    • std::cout is a special case
    • Nothing worse than output interleaving can happen
  • The consequences of a data race can be much more serious

    • Incorrect results
    • Incorrect program flow
    • "Torn" writes and reads
    • Objects which are improperly constructed or destroyed