Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
C++ System Programming Cookbook

You're reading from   C++ System Programming Cookbook Practical recipes for Linux system-level programming using the latest C++ features

Arrow left icon
Product type Paperback
Published in Feb 2020
Publisher Packt
ISBN-13 9781838646554
Length 292 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Onorato Vaticone Onorato Vaticone
Author Profile Icon Onorato Vaticone
Onorato Vaticone
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Getting Started with System Programming 2. Revisiting C++ FREE CHAPTER 3. Dealing with Processes and Threads 4. Deep Dive into Memory Management 5. Using Mutexes, Semaphores, and Condition Variables 6. Pipes, First-In First-Out (FIFO), Message Queues, and Shared Memory 7. Network Programming 8. Dealing with Console I/O and Files 9. Dealing with Time Interfaces 10. Managing Signals 11. Scheduling 12. Other Books You May Enjoy

Learning how atomic works

Traditionally, C and C++ have a long tradition of portable code for system programming. The atomic feature that was introduced in the C++11 standard reinforces this by adding, natively, the guarantee that an operation is seen as atomic by other threads. Atomic is a template, such as template <class T> struct atomic; or template <class T> struct atomic<T*>;. C++20 has added shared_ptr and weak_ptr to T and T*. Any operation that's performed on the atomic variable is now protected from other threads.

How to do it...

std::atomic is an important aspect of modern C++ for dealing with concurrency. Let's write some code to master the concept:

  1. The first snippet of code shows the basics of atomic operations. Let's write this now:
std::atomic<int> speed (0);         // Other threads have access to the speed variable
auto currentSpeed = speed.load(); // default memory order: memory_order_seq_cst
  1. In this second program, we can see that the is_lock_free() method returns true if the implementation is lock-free or if it has been implemented using a lock. Let's write this code:
#include <iostream>
#include <utility>
#include <atomic>
struct MyArray { int z[50]; };
struct MyStr { int a, b; };
int main()
{
std::atomic<MyArray> myArray;
std::atomic<MyStr> myStr;
std::cout << std::boolalpha
<< "std::atomic<myArray> is lock free? "
<< std::atomic_is_lock_free(&myArray) << std::endl
<< "std::atomic<myStr> is lock free? "
<< std::atomic_is_lock_free(&myStr) << std::endl;
}
  1. Let's compile the program. When doing so, you may need to add the atomic library to g++ (due to a GCC bug) with g++ atomic.cpp -latomic.

How it works...

std::atomic<int> speed (0); defines a speed variable as an atomic integer. Although the variable will be atomic, this initialization is not atomic! Instead, the following code: speed +=10; atomically increases the speed of 10. This means that there will not be race conditions. By definition, a race condition happens when among the threads accessing a variable, at least 1 is a writer.

The std::cout << "current speed is: " << speed; instruction reads the current value of the speed automatically. Pay attention to the fact that reading the value from speed is atomic but what happens next is not atomic (that is, printing it through cout). The rule is that read and write are atomic but the surrounding operations are not, as we've seen.

The output of the second program is as follows:

The basic operations for atomic are load, store, swap, and cas (short for compare and swap), which are available on all types of atomics. Others are available, depending on the types (for example, fetch_add).

One question remains open, though. How come myArray uses locks and myStr is lock-free? The reason is simple: C++ provides a lock-free implementation for all the primitive types, and the variables inside MyStr are primitive types. A user will set myStr.a and myStr.b. MyArray, on the other hand, is not a fundamental type, so the underlying implementation will use locks.

The standard guarantee is that for each atomic operation, every thread will make progress. One important aspect to keep in mind is that the compiler makes code optimizations quite often. The use of atomics imposes restrictions on the compiler regarding how the code can be reordered. An example of a restriction is that no code that preceded the write of an atomic variable can be moved after the atomic write.

There's more...

In this recipe, we've used the default memory model called memory_order_seq_cst. Some other memory models that are available are:

  • memory_order_relaxed: Only the current operation atomicity is guaranteed. That is, there are no guarantees on how memory accesses in different threads are ordered with respect to the atomic operation.
  • memory_order_consume: The operation is ordered to happen once all accesses to memory in the releasing thread that carry a dependency on the releasing operation have happened.
  • memory_order_acquire: The operation is ordered to happen once all accesses to memory in the releasing thread have happened.
  • memory_order_release: The operation is ordered to happen before a consume or acquire operation.
  • memory_order_seq_cst: The operation is sequentially consistent ordered.

See also

The books Effective Modern C++ by Scott Meyers and The C++ Programming Language by Bjarne Stroustrup cover these topics in great detail. Furthermore, the Atomic Weapons talk from Herb Sutter, freely available on YouTube (https://www.youtube.com/watch?v=A8eCGOqgvH4), is a great introduction.

You have been reading a chapter from
C++ System Programming Cookbook
Published in: Feb 2020
Publisher: Packt
ISBN-13: 9781838646554
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Visually different images