Cache line sharing between processors. False sharing. Data race condition?

124 Views Asked by At

Trying to simulate data race for code:

struct Foo
{
  // ~ 3100ms
  alignas(std::hardware_destructive_interference_size) std::atomic<int> Counter1 = 0;
  alignas(std::hardware_destructive_interference_size) std::atomic<int> Counter2 = 0;

  // ~ 5900ms
  //std::atomic<int> Counter1 = 0;
  //std::atomic<int> Counter2 = 0;

  // ~ 130ms
  //alignas(std::hardware_destructive_interference_size) int Counter1 = 0;
  //alignas(std::hardware_destructive_interference_size) int Counter2 = 0;

  // ~ 270ms
  //int Counter1 = 0;
  //int Counter2 = 0;
};

int main()
{
  Foo       FooObj;
  const int IncrementsByThread = 100000000;

  std::thread T1([&FooObj, IncrementsByThread](){
      for (int i = 0; i < IncrementsByThread; i++)
        FooObj.Counter1++;
    });

  std::thread T2([&FooObj, IncrementsByThread](){
      for (int i = 0; i < IncrementsByThread; i++)
        FooObj.Counter2++;
    });

  T1.join();
  T2.join();

  std::cout << "Counters are " << FooObj.Counter1 << ", " << FooObj.Counter2 << std::endl;

  return 0;
}

Result always the same, counters are equal, there are no data races. But false sharing exists without aligned data.

Not aligned Counter1 and Counter2 placed next to each other in memory, so cache line holds both of them. Have false sharing. After alignas() false sharing fixed.

But I thought there would be data race in case simple int Counters without alignas(). Looks like we have cache coherence working at all 4 cases with atomics, simple int, alignas()?

When do cache coherence protocols works? Thought only in cases atomic operations

Tryied to use atomics, alignas() to avoid false sharing. One int Counter makes data races, it is obviously, but I was thinking that simple non-atomic counters nearly placed in memory holding 1 cache line can produce data race situation and will be Counter1 != Counter2.

0

There are 0 best solutions below