Acquire-Release Semantic

Contents[Show]

With the acquire-release semantics, the memory model gets very thrilling. Because now, we do not have to reason about the synchronization of threads, we have to reason about the synchronization of the same atomic in different threads.

Synchronization and Ordering Constraints

The acquire-release semantic is based on one key idea. A release operation synchronizes with an acquire operation on the same atomic and establishes, in addition, an ordering constraint. So, all read and write operations can not be moved before an acquire operation; all read and write operations can not be moved behind a release operation. But what is an acquire or release operation? Reading an atomic variable with load or test_and_set is an acquire operation. But in addition, the acquiring of a lock. Of course, the opposite is also true. The releasing of a lock is a release operation—accordingly, a store or clear operation on an atomic variable.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

It's worth more reasoning on the few last sentences from a different perspective. The lock of a mutex is an acquire operation; the unlock of a mutex is a release operation. That implies that an operation on a variable can not be moved outside of a critical section. That hold for both directions. On the other side, a variable can be moved inside of a critical section. Because the variable moves from the not protected to the protected area. Now with a little delay, the picture.

 

criticalRegion

Did II not promise it? The acquire-release semantics helps understand the lock better and unlock operation of a mutex. The same reasoning will hold for the starting of a thread or the join-call on a thread. Both are release operations. But that story continues with the wait and notify_one-call on a condition variable. wait is this case is the acquire, notify_one the release operation. But what is about notify_all? Of course, you can already guess it. That is a release operation.

Because of the theory, I can write the spinlock from the post The atomic flag is more efficient because the synchronization takes place on the atomic variable flag.

 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
26
27
28
29
30
31
32
33
34
35
36
37
// spinlockAcquireRelease.cpp

#include <atomic>
#include <thread>

class Spinlock{
  std::atomic_flag flag;
public:
  Spinlock(): flag(ATOMIC_FLAG_INIT) {}

  void lock(){
    while(flag.test_and_set(std::memory_order_acquire) );
  }

  void unlock(){
    flag.clear(std::memory_order_release);
  }
};

Spinlock spin;

void workOnResource(){
  spin.lock();
  // shared resource
  spin.unlock();
}


int main(){

  std::thread t(workOnResource);
  std::thread t2(workOnResource);

  t.join();
  t2.join();

}

 

The flag.clear-call in line 16 is a release, and the flag.test_and_set-call in line 12 is an acquire-operation. And - but that is boring - the acquire synchronizes with the release operation. So the heavyweight synchronization with sequential consistency (std::memory_order_seq_cst) of two threads is replaced with the lightweight and more performant acquire-release semantic (std::memory_order_acquire and std::memory_order_release). The behavior is unchanged.

In case more than two threads use the spinlock, the acquire semantics of the lock method is not sufficient. Now the lock method is an acquire-release operation. So the memory model in line 12 has to be changed to std::memory_order_acq_rel. But that is still cheaper than the default: std::memory_order_seq_cst.

 

What's next?

Our journey through the memory model continues in the next post with the transitivity of the acquire-release semantic. So you can synchronize threads that share no atomic.

 

 

 

 

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Comments   

-1 #1 apk files 2016-10-26 10:52
I love it when people come together and share thoughts.
Great site, stick with it!
Quote
-1 #2 APK Download 2016-10-28 19:22
Hello i am kavin, its my first occasion to commenting anyplace,
when i read this article i thought i could also create comment due to this brilliant paragraph.
Quote
-1 #3 APK Download 2016-12-23 20:57
This is a very good tip particularly to those new to the blogosphere.
Brief but very precise info… Appreciate your sharing this one.
A must read article!
Quote
+1 #4 DM 2020-03-10 05:37
This is a great serial of articles which help solved my so many years confuse. But it also gives me a new confuse at the end of this article -- "In case more than two threads uses the spinlock, the acquire semantic of the lock method is not sufficient." why? and why it must be more than 2 thread, not 2?
Quote
+1 #5 Rainer Grimm 2020-03-13 12:06
Quoting DM:
This is a great serial of articles which help solved my so many years confuse. But it also gives me a new confuse at the end of this article -- "In case more than two threads uses the spinlock, the acquire semantic of the lock method is not sufficient." why? and why it must be more than 2 thread, not 2?

With two threads a total order of the unlock/lock calls is sufficient. With more than two threads, you need also a total order on the lock calls. Each lock call has to synchronize with all other lock calls. An acquire on a lock has to synchronise with a release on the same lock.
Quote
+1 #6 Prateek Gupta 2020-08-16 08:13
Quoting Rainer Grimm:
Quoting DM:
This is a great serial of articles which help solved my so many years confuse. But it also gives me a new confuse at the end of this article -- "In case more than two threads uses the spinlock, the acquire semantic of the lock method is not sufficient." why? and why it must be more than 2 thread, not 2?

With two threads a total order of the unlock/lock calls is sufficient. With more than two threads, you need also a total order on the lock calls. Each lock call has to synchronize with all other lock calls. An acquire on a lock has to synchronise with a release on the same lock.

I still did not get it why we need to change the memory ordering from acquire to acquire release when more than 2 threads are used.
Quote
0 #7 hpc 2020-09-02 13:00
Quoting Prateek Gupta:
Quoting Rainer Grimm:
Quoting DM:
This is a great serial of articles which help solved my so many years confuse. But it also gives me a new confuse at the end of this article -- "In case more than two threads uses the spinlock, the acquire semantic of the lock method is not sufficient." why? and why it must be more than 2 thread, not 2?

With two threads a total order of the unlock/lock calls is sufficient. With more than two threads, you need also a total order on the lock calls. Each lock call has to synchronize with all other lock calls. An acquire on a lock has to synchronise with a release on the same lock.

I still did not get it why we need to change the memory ordering from acquire to acquire release when more than 2 threads are used.


Even if multiple threads content for the lock the synchronization is always between 2 threads: the one that wants the lock and the one that owns the lock. No synchroization es needed among the threads that want the lock.
So the synchronization with just acquire-release is fine.
Quote

Stay Informed about my Mentoring

 

Mentoring

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 4300

Yesterday 6193

Week 10493

Month 32167

All 12110376

Currently are 166 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments