Ongoing Optimization: A Data Race with CppMem

Contents[Show]

But we can do better and further improve the acquire-release semantic of the last post. Why should x be an atomic? There is no reason. That was my first, but incorrect assumption. See why?

A typical misunderstanding in the application of the acquire-release semantic is, to assume, that the acquire operation is waiting for the release operation. So based on this assumption you may think, that x has not to be an atomic variable. So we can further optimize the program.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ongoingOptimizationAcquireReleaseBroken.cpp

#include <atomic>
#include <iostream>
#include <thread>

int x= 0;
std::atomic<int> y{0};

void writing(){  
  x= 2000;  
  y.store(11,std::memory_order_release);
}

void reading(){  
  std::cout << y.load(std::memory_order_acquire) << " ";  
  std::cout << x << std::endl;
}

int main(){
  std::thread thread1(writing);
  std::thread thread2(reading);
  thread1.join();
  thread2.join();
};

 

The program has a data race on x and has therefore undefined behaviour. If y.store(11,std::memory_order_release) (line 12) is executed before  y.load(std::memory_order_acquire) (line 16), the acquire-release semantic guarantees, that x= 2000 (line 11) is executed before the reading of x in line 17. But if not. In this case, the reading of x will be executed at the same time as the writing of x. So we have concurrent access on a shared variable, one of them is a write. That's per definition a data race. 

The table puts it in a nutshell.

undefinedEng

 

I made this mistake in my presentation "Mulithreading done right?" in Berlin. In Moscow, I did it right. I never claimed, that the C++ memory model is a piece of cake.

Now its time for CppMem. Let's see, what CppMem finds out.

CppMem

 

int main(){
  int x= 0;
  atomic_int y= 0;
  {{{ { 
      x= 2000;
      y.store(11,memory_order_release);
      }
  ||| {
      y.load(memory_order_acquire);
      x;
      }
  }}}
}

The data race occurs, if one thread is writing x= 2000 and the other thread is reading x. In the graph, we get a dr symbol (data race) on the arrow.

raceAcquireRelease

What's next?

The ultimate step in the process of ongoing optimization is still missing. In the next post, I will use the relaxed semantic.

 

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Get your e-book. Support my blog.

 

Comments   

0 #1 best songs dubstep 2016-10-12 16:55
Good way of telling, and pleasant paragraph to get data about my presentation subject,
which i am going to present in college.
Quote

Add comment


My Newest E-Book

Latest comments

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 93

All 333384

Currently are 172 guests and no members online