Learn Useful Bidirectional Fences In Modern Multi-threading C++ Apps

C++11 improved the support for bidirectional fences in multi-thread applications. In modern C++ developmentFences are synchronization primitives in multi-threading operations, they are memory barriers in threads, and they can acquire semantics, release semantics, or both. In this post, we explain what are fences and how we can use them.

What are bidirectional fences in C++?

A fence is a primitive that enforces ordering between preceding loads or stores and subsequent loads or stores. C++11 improves the support for bidirectional fences. Fences are synchronization primitives in multi-threading operations they can have acquire semantics, release semantics, or both of them. A fence with acquire semantics is called an acquire fence and a fence with release semantics is called a release fence. If both operations are done, we call them full fence

In modern C++, std::atomic_thread_fence is called fences, they are memory barriers in multi-thread operations, and they establish synchronization and ordering constraints between each thread without any atomic operation. In other words, std::atomic_thread_fence establishes memory synchronization ordering of non-atomic and relaxed atomic accesses without an associated atomic operation.

How to use bidirectional fences in C++?

Fences are useful between load and store operations and there are 4 types .

  • LoadLoad : A load followed by a load
  • LoadStore : A load followed by a store
  • StoreLoad : A store followed by a load
  • StoreStore : A store followed by a store

Here is the syntax how we can use std::atomic_thread_fence,

Here are two simple examples how to use in release and acquire operations of thread functions,

according to open-std.org document , depending on the value of memory_order, this operation it has different effects,

  • if order == memory_order_relaxed; it has no effects,
  • if order == memory_order_acquire || order == memory_order_consume; it is an acquire fence,
  • if order == memory_order_release; it is a release fence,
  • if order == memory_order_acq_rel; it is both an acquire fence and a release fence, (full fence)
  • if order == memory_order_seq_cst; it is a sequentially consistent acquire and release fence

Is there a full C++ example of how to use bidirectional fences in C++?

Let’s assume we have two threads one is writing to data other one is reading

In different runs, you will receive different R and A prints, for example,

In this example above, we want all operations to be done in the first thread, thus we can use std::atomic_thread_fence as below,

here is the output,

In C++, there is another fence option, std::atomic_signal_fence is another fence type that synchronizes between a signal handler and code running on the same thread. This will be explained in another post.

For more information about bidirectional fences, please see Bidirectional Fences Proposal document.

Learn Useful Bidirectional Fences In Modern Multi threading C++ Apps C++ Builder logo

C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.

There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.