Development c

How To Use Propagating Exceptions In Modern C++?

Modern C++ has many features to aid multi-thread programming that allow applications to be faster and more responsive. The C++11 standard offers the possibility of moving an exception from one thread to another. This type of movement is called propagating exceptions, exception propagation; also known as rethrow exception in multi-threading. To do that, some modifications have been made to the header in C++ and there is a nullable pointer-like type std::exception_ptr. In this post, we explain std::exception_ptr and how to use the rethrow exception method in modern C++. What are propagating exceptions (exception propagation) in modern C++? The C++11 standard offers a nullable pointer-like type std::exception_ptr. The exception_ptr is used to refer to an exception and manages an exception object that has been thrown and captured with std::current_exception(). Here is how we can use both:   std::exception_ptr e = std::current_exception();   In modern C++, a concurrency support library is designed to solve problems in multi-thread operations. This library includes built-in support for threads (std::thread), atomic operations (std::atomic), mutual exclusion (std::mutex), condition variables (std::condition_variable), and many other features. In addition to these useful features, std::exception_ptr is useful in exception handling between threads. They may be passed to another function, possibly to another thread function, so that the exception can be rethrown and handled in another thread with a catch clause. According to open-std, “An exception_ptr that refers to the currently handled exception or a copy of the currently handled exception, or a null exception_ptr if no exception is being handled. If the function needs to allocate memory and the attempt fails, it returns an exception_ptr that refers to an instance of bad_alloc. It is unspecified whether the return values of two successive calls to current_exception refer to the same exception.” The exception_ptr can be DefaultConstructible, CopyConstructible, Assignable and EqualityComparable. By default, it is constructed as a null pointer, doesn’t point to an exception, and operations from exception_ptr do not throw. Is there a simple example of how to use propagating exceptions in modern C++? Here is a simple example that outputs exceptions coming from a thread. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17   std::mutex m;   void throw_exception( std::exception_ptr e) { try { if (e) std::rethrow_exception(e); } catch(const std::exception& e) { m.lock(); std::cout

Read More

How to Use Atomic_flag In Modern C++?

C++11 allows the use of atomics in signal handlers. In C++17 the signal handler feature is further improved. The std::atomic_flag is an atomic boolean type that is guaranteed to be lock-free and can be used in signal handlers. Moreover, the  header in C++ has an integer type std::sig_atomic_t that can be accessed as an atomic entity even in the presence of asynchronous interrupts made by signals. In this post, we explain how to use atomic_flag in C++. What is atomic_flag in C++? The std::atomic_flag is a flag in the atomics library which is known as an atomic boolean type. The std::atomic is guaranteed to be lock-and does not provide load or store operations. In addition, they provide synchronization and order constraints on the program execution. Here is the general syntax since C++11.   std::atomic_flag ;   Here is how we can declare it.   std::atomic_flag flag = ATOMIC_FLAG_INIT;   What are the features of atomic_flag in modern C++? The std::atomic_flag has useful features, these are as follows. The clear() feature is used to set flags to false atomically, in example we can use it with a memory_order as below,   flag.clear(std::memory_order_release);   test_and_set() tests the flag to true and obtains its previous value, in example we can use it with a memory_order in a while loop as we show in the example below:   while (flag.test_and_set(std::memory_order_acquire)) // acquire flag { }   The test() feature is new in C++20, returns the value of the flag atomically, like so:   while ( flag.test(std::memory_order_relaxed) ) // release flag { }   The wait() feature is new in C++20 and it blocks the thread until the atomic value changes and it is notified. Here is an example:   wait ( true, std::memory_order_relaxed);   in C++20, there are notify_one() and notify_all() features too. Note that, std::atomic_flag is a pretty low-level type – you can consider using atomic_bool instead. Also, you can use member functions with the set and the clear methods. You can also use higher level constructs, such as a std::mutex and std:: lock_guard. How to use atomic_flag in modern C++? Here is an atomic_flag C++ example. 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   #include #include #include #include #include   #include   std::atomic_flag flag = ATOMIC_FLAG_INIT;   std::stringstream stream;   void myf(int x) {   while ( flag.test_and_set() ) {}   stream

Read More

What Is Weak Compare and Exchange In Modern C++?

Since the C++11 standard, the Concurrency Support Library includes built-in support for threads (std::thread) with atomic operations (std::atomic). C++11 provides both weak and strong compare-and-exchange operations in multi-threading applications. Since C++11, weak compare and exchange are used in modern C++ standards such as C++14, C++17, C++20, and in other new standards. In this post, we explain weak compare and exchange with simple examples. What is weak compare and exchange in C++? The Weak Compare and Exchange template atomically compares the value pointed to by the atomic object with the value pointed to by expected. This feature comes with C++11 and is used in other modern C++ standards. and performs the following operations based on the comparison results: If the comparison result is true (bitwise-equal), the function replaces the value pointed to by the atomic object with the value desired. If the comparison result is false, the function updates the value in expected with the value pointed by the atomic object There are two most common syntaxes for the compare_exchange_weak, first,   bool compare_exchange_weak( T& expected, T desired) noexcept;   and in weak compare and exchange atomic operations, we can use std::compare_exchange_weak template with memory order types. Here is the syntax for the compare_exchange_weak with memory orders,   bool compare_exchange_weak( T& expected, T desired,                               std::memory_order success,                               std::memory_order failure ) noexcept;   here is how we can use it,   std::atomic x;   exchanged = x.compare_exchange_weak( expected, desired);   exchanged = x.compare_exchange_weak( expected, desired, std::memory_order_release, std::memory_order_relaxed);   Note that, providing both compare_exchange_strong and compare_exchange_weak allow us to decide whether we want the library to handle spurious failures (using compare_exchange_strong) or if we want to handle it in our own code (using compare_exchange_weak). The compare_exchange_strong needs extra overhead to retry in the case of failure. For details please see Load-link/store-conditional in Wikipedia. Is there a simple example of weak compare and exchange in C++? Here is a simple example about weak compare and exchange in C++. Let’s assume we have a thread function myf1() that ensures value is changed after a weak compare and exchange. This is how we can do this,   void myf1(int desired) { int expected = 1; bool exchanged;   do { exchanged = x.compare_exchange_weak( expected, desired ); std::cout

Read More

Important To Learn std::memory_order In C++ Atomic Operations

Using multi-threading development skills on the CPU, GPU, and memory operations is important in programming, but it can give rise to problems in synchronization of multi-thread operations and reaching data for reading and writing. The concurrency support library in modern C++ is designed to solve problems in multi-thread operations. Since the C++11 standard, this library includes built-in support for threads (std::thread) with atomic operations (std::atomic). The memory_order type definition defines how to access memory in multi-thread operations, including atomic, regular, and non-atomic memory accesses. In this post, we explain how to use std::memory_order in modern multi-threading operations. Concurrent programming is highly evolved and inherently diverse, and includes high-performance multi-threading and parallel programming features, asynchronous task processing, message-based and event-based systems, non-blocking, lock-free, and optimistic data structures, transactional approaches, and many other features to build multi-threading applications. The memory_order feature is one of the most important parts of the new C++ standards. For example, the C++20 standard has about 653 “memory_order” keywords if you perform a search. In other words, it means it has a very important role in atomic and atomic operations in multi-threading applications. Before this, let’s remind ourselves about std::atomic in C++. What is atomic (std::atomic) in C++? C++11 adds atomic types and operations to the standard. Atomic types and operations provide a way of writing multi-threaded applications without using locks. In modern C++, the std::atomic template class is defined in the header and it can be used to wrap other types to do atomic operations on that type. When a thread writes to an atomic object another thread can read from it. Every instantiation and full specialization of the std::atomic template defines an atomic type. Atomic types ensure any read or write operation synchronizes as part of multi-thread operations, (i.e. using these types in std::thread). They work well on private types (i.e. int, float, double, etc.) or any type that is trivially copyable types which means it has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator and has non-deleted trivial destructor. Here is a simple syntax for the atomic declaration:   atomic type_name;   Here is a simple std::atomic example:   std::atomic counter(0); // atomic type   void myf() // a function to be used in multi-thread operations {    counter++; // atomic operation }   Atomic operations are operations on the of values atomic types (std::atomic objects) in the atomic library that allows lockless concurrent programming. These operations are good in data races and these objects are free of data races. Different atomic operations can be done on the same atomic object in their sync. std::atomic has many features to be used in atomic operations, i.e. load, store, operator=, wait, exchange, is_lock_free, etc. Let’s see these load and store operations now. What is std::memory_order in C++ atomic operations? The memory_order type definition defines how to access memory in multi-thread operations, including atomic, regular, and non-atomic memory accesses. The memory_order type definition is used in multi-thread atomic operations when multiple threads simultaneously read and write to different variables in memory. In this concept, threads can observe the value changes in order or threads written into atomic types within memory order. Here is the definition syntax from C++11 to C++17,   typedef enum memory_order {     memory_order_relaxed,     memory_order_consume,     memory_order_acquire,     memory_order_release,     memory_order_acq_rel,     memory_order_seq_cst } memory_order;   Since C++20, there are changes on this […]

Read More

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++ development, Fences 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,   extern “C” void atomic_thread_fence( std::memory_order order ) noexcept;   Here are two simple examples how to use in release and acquire operations of thread functions,   void myf1() {       atomic_thread_fence(std::memory_order_release); }     void myf2() {          atomic_thread_fence(std::memory_order_acquire); }   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 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   #include #include   int x[500];   void myf1() { for (int i = 0; i

Read More

What Is A Data Race In Multi-threading C++ Apps And How To Avoid It

In modern programming, if you are developing multithreaded applications, data races are a common problem in threads. Data races occur when multiple tasks or threads access a shared resource without sufficient protection, leading to undefined or unpredictable behavior on runtime. You can imagine two or more task threads in cores trying to reach the same data in a race. In this post, we explain what a data race is and how to avoid it in modern C++. What is data race in multi-threading C++ apps? We use multi-threading code when we want to handle multiple tasks to speed up functions or algorithms. Multithreaded programming is easy with the concurrency support library in C++. However, if you don’t know how to reach each data type, multi-thread operations can be highly complex and introduce subtle defects such as data races and deadlocks. At this time, defects occur on runtime or at outputs, this may take a long time to reproduce the issue and even longer to identify the root cause and fix the defect. In general, more than one thread accesses the same memory location simultaneously, and at least one writes in data race situations. That means there is a conflict in memory access. Is there an example of a data race in C++? Assume that we have a computer shop, and we have items in the store. We move them from shop to store and from store to shop. We have many staff (threads) that transfer these items from store to shop or shop to store. Different staff may access the store or shop at the same time. In this simple data race example, the same thread function ( transfer_items() ) reads and writes two different variables (store_items and shop_items) where they show the number of items in store and shop. Here is a full example, 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   #include #include   int store_items = 20; int shop_items = 0; //—————————————————————— void transfer_items(int amount, int& out, int& in) {   out -= amount;   std::this_thread::sleep_for(std::chrono::nanoseconds(10));   in += amount; } //—————————————————————— int main() {   std::cout

Read More

How To Solve Data Race Problems In Modern C++?

In multi-thread programming, data races are a common problem in threads. Data races occur when multiple tasks or threads access a shared resource without sufficient protection, leading to undefined or unpredictable behavior on runtime. In C++, the concurrency support library is designed to solve these kinds of data race problems. In this post, we explain how to solve data race problems in modern C++. What is data race in multi-threading C++ apps? We use multi-threading code when we want to handle multiple tasks to speed up functions or algorithms. Multithreaded programming is easy with the concurrency support library in C++. However, if you don’t know how to reach each data type, multi-thread operations can be highly complex and introduce subtle defects such as data races and deadlocks. At this time, defects occur on runtime or at outputs, this may take a long time to reproduce the issue and even longer to identify the root cause and fix the defect. How can we solve data race problems with modern C++? If you have a problem in your multi-threading application and you understand that is about data racing in threads. First, if your app is popular and you want to fix and release it quickly, set it to a single thread (slower but faster and safer and gives you time to solve the problem). Thus, your application may run, with slower performance, but no defects during runtime. Now we can focus on our real problem. First, know that the data race problem is about accessing your data in usage in your threads. Try to find which thread is causing this, and what type of data could be having a situation that at least one operation in threads trying to write. Debugging in thread operations may help you and try to slow your thread by using sleep_for in threads.   std::this_thread::sleep_for(std::chrono::milliseconds(1000));   If your debugger doesn’t help, you can ‘comment’ some parts of data write operations. Inside a thread, between the suspicious lines, you can add some printouts into a variable (to string lists for example) to see each operation step in debug before the error occurs. In deep, you can use every feature of the concurrency support library in C++, we highly recommend you C++17 or higher compilers to achieve better results in usage. Use std::thread, and std::atomic with atomic types and operations (load, store), and you can use memory order (std::memory_order) models in different situations. Moreover, you can use fences (std::atomic_thread_fence), mutex (std::mutex) and other blocking or locking methods in threads.  The concurrency support library is designed to solve these kinds of data race problems. This is your exact solution and there might be different ways to solve with different concurrency features in modern C++. Note that, there might be slight differences in operational speed and thread usage, so you should decide which feature is the best for your thread function or functions. They may help your algorithm to speed up and to be safer too. Solving multi-thread problems may require high programming skills, if you are still unable to solve problems, you may get additional support from senior C++ developers or supporter developers of your IDE and compiler. Is there a data race example in modern C++? Assume that we have a computer shop and we have items in the store. We move them from […]

Read More

Learn Strong Compare and Exchange In Modern C++

Since the C++11 standard, the Concurrency Support Library includes built-in support for threads (std::thread) with atomic operations (std::atomic). C++11 provides both weak and strong compare-and-exchange operations in multi-threading applications. Since C++11, strong compare and exchange are used in modern C++ standards such as C++14, C++17, C++20, and in other new standards. In this post, we explain what is strong compare and exchange is with simple examples. What is strong compare and exchange in C++? The Strong Compare and Exchange template atomically compares the value pointed to by the atomic object with the value pointed to by expected. This feature comes with C++11 and is used in other modern C++ standards, and performs the following operations based on the comparison results: If the comparison result is true (bitwise-equal), the function replaces the value pointed to by the atomic object with the value desired. If the comparison result is false, the function updates the value in expected with the value pointed by the atomic object. There are two most common syntaxes, here is the syntax for the compare_exchange_strong, first,   bool compare_exchange_strong( T& expected, T desired) noexcept;   and in strong compare and exchange atomic operations, we can use std::compare_exchange_strong template with memory order types. Here is the syntax for the compare_exchange_strong with memory orders,   bool compare_exchange_strong( T& expected, T desired,                               std::memory_order success,                               std::memory_order failure ) noexcept;   here is how we can use it,   std::atomic x;   exchanged = x.compare_exchange_strong( expected, desired);   exchanged = x.compare_exchange_strong( expected, desired, std::memory_order_release, std::memory_order_relaxed);   Note that providing both compare_exchange_strong and compare_exchange_weak allows us to decide whether we want the library to handle spurious failures (using compare_exchange_strong) or if we want to handle it in ourr own code (using compare_exchange_weak). The compare_exchange_strong needs extra overhead to retry in the case of failure. For details, please see Load-link/store-conditional in Wikipedia. Is there a simple example of strong compare and exchange in C++? Here is a simple example about strong compare and exchange in modern C++. Let’s assume we have a thread function myf1() that ensures value is changed after a strong compare and exchange. This is how we can do this,   void myf1(int desired) { int expected = 1; bool exchanged;   do { exchanged = x.compare_exchange_strong( expected, desired ); std::cout

Read More

What Is A Virtual Function Specifier In Modern C++?

In modern C++ software, a virtual function is a function in a base class or struct that can be redefined in derived classes or structs. They are member functions whose behavior can be overridden in derived classes. The virtual function specifier is the ‘virtual’ specifier to declare a virtual function in a base class. In this post, we explain how we can use virtual function specifiers in modern C++. What is a virtual function specifier in modern C++? A virtual function is a function in a base class or struct that can be redefined in derived classes or structs. They are member functions whose behavior can be overridden in derived classes. The virtual function specifier is the ‘virtual‘ specifier to declare a virtual function in a base class. It is used by declaring the function prototype in the usual way and then prefixing the declaration with the virtual keyword. Here is the syntax of a virtual function:   virtual function_declaration;   To declare a pure function (which automatically declares an abstract class), prefix the prototype with the virtual keyword, and set the function equal to zero. Here is an example to virtual function and pure virtual function in C++:   virtual int funct1(void);       // A virtual function declaration.   virtual int funct2(void) = 0;   // A pure function declaration.   How to use virtual function specifier in modern C++? When you declare virtual functions, keep these guidelines in mind: They can be member functions only. They can be declared a friend of another class. They cannot be a static member. A virtual function does not need to be redefined in a derived class. You can supply one definition in the base class so that all calls will access the base function. To redefine a virtual function in any derived class, the number and type of arguments must be the same in the base class declaration and in the derived class declaration. The case for redefined virtual functions differing only in return type is discussed below. A redefined function is said to override the base class function. You can also declare the functions int Base::Fun(int) and int Derived::Fun(int) even when they are not virtual. In such a case, int Derived::Fun(int) is said to hide any other versions of Fun(int) that exist in any base classes. In addition, if class Derived defines other versions of Fun(), (that is, versions of Fun() with different signatures) such versions are said to be overloaded versions of Fun(). Is there a simple example of a virtual function in modern C++? Here is a simple example how you can use virtual function specifier in modern C++. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17   class Tx { virtual void myf() { std::cout

Read More

What Is An Explicit Virtual Override in Modern C++?

Modern C++ has many additions compared to the original C++ standard. Regarding virtual overrides, C++11 tends to tighten the rules, to detect some problems that often arise. To achieve this goal C++11 introduces two new contextual keywords, the final and the override specifiers. The override specifier is used to redefine the base class function in a derived class with the same signature i.e. return type and parameters. This override specifier is used with the C++ compiler that has C++11 and the other higher C++ standards. In this post, we explain an override specifier in modern C++. What Is the override specifier in C++? The override specifier (keyword) is used to redefine the base class function in a derived class with the same signature i.e. return type and parameters. In other words, it specifies that a method overrides a virtual method declared in one of its parent classes. Regarding virtual overrides, C++11 tends to tighten the rules, to detect some problems that often arise. To achieve this goal C++11 introduces two new contextual keywords: Final specifies that a method cannot be overridden, or a class cannot be derived. Override specifies that a method overrides a virtual method declared in one of its parent classes. The override specifier generally has two purposes, It shows that a given virtual method is overriding a virtual method of the base class. It indicates to the compiler that you are not adding or altering new methods that you think are overrides, and the compiler knows that is an override. In this post, we explain how to use the override specifier in C++. How to use the override specifier in C++? The override specifier is used to designate member functions that override a virtual function in a base class.   function_declaration override;   and, here is an example:   class Tbase { virtual void a(); };   class Tx : Tbase { void a() override; };   Is there a simple example to explicit virtual override specifier in C++ ? Here is a simple class example about override and final specifiers that you can override a method of it. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24   #include   class Tbase { virtual void a(); void b(); virtual void c() final; virtual void d(); };   class Tx : Tbase { void a() override; // correct // void b() override; // error, an override can only be used for virtual functions // void c() override; // error, cannot override a function marked as final // int d() override; // error, different return type };   int main() {     class Tx o1; }   Here is a simple struct example about override and final specifiers that you can override a method of it. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24   #include   struct st_base { virtual void a(); void b(); virtual void c() final; virtual void d(); };   struct st_x : st_base { void a() override; // correct // void b() override; // error, an override can only be used for virtual functions // void c() override; // error, cannot override a function marked as final // int d() override; // error, […]

Read More