Noutați

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

Introducing CMake Debugger in VS Code: Debug your CMake Scripts using Open-Source CMake Debugger

Introducing CMake Debugger in VS Code: Debug your CMake Scripts using Open-Source CMake Debugger Sinem Akinci August 9th, 20231 2 The new CMake Debugger that was introduced in Visual Studio is now available in VS Code. Now, you can debug your CMakeLists.txt scripts from VS Code using the CMake Tools Extension. To see the full release notes for this release and what else is included, including bug fixes, please see the release notes. Background The Visual C++ team collaborated closely with Kitware, the CMake maintainers, to merge our CMake debugger implementation upstream and make this widely available. This implementation is now available in CMake version 3.27. Please download the latest version for your OS via this link or update via your system package manager to access the CMake debugger in VS Code. You can check your CMake version on your machine at any time by running cmake –version in a terminal window. CMake 3.27 will ship with Visual Studio in a later release in 17.8. The debugger uses the widely supported Debug Adapter Protocol, which is compatible with many development environments.  We are excited to see how the open-source community works together to implement new ideas for the debugger. CMake Debugger Functionality As a user, you’ll see the same functionality as you would in a normal debugging session. This includes viewing variables, call stacks, and cache variables specific to CMake and the ability to set breakpoints on your CMakeLists.txt file and step through your code. To open the CMake Debugger in your project, you can select it from the command palette by pressingCtrl+Shift+P. Additionally, it can be opened anywhere else you typically configure your project, such as in the CMake Project Outline in the CMake Tools side panel. If your CMake configure ever fails, a notification will pop-up for you to interact with to launch the debugger. What’s next? Next up, we are working on a few different things including implementing CMake language services and re-vamping our overall CMake side panel and status bar experiences based on user feedback. Let us know what else you’d like to see! Send us your feedback! We hope this helps your CMake workflows in VS Code. Download the latest preview version of Visual Studio and give it a try. Download the CMake Tools extension for Visual Studio Code and let us know what you think. We would love to see what you contribute to our repo and are active on reviews and collaboration. If you have any issues, please file an issue to our repo here. Comment below or reach us via email at visualcpp@microsoft.com or via Twitter at @VisualC. Sinem Akinci Program Manager II, Visual C++ Team Follow

Read More

MSVC Address Sanitizer – One DLL for all Runtime Configurations

MSVC Address Sanitizer – One DLL for all Runtime Configurations Amy Wishnousky August 10th, 20231 2 With Visual Studio 2022 version 17.7 Preview 3, we have refactored the MSVC Address Sanitizer (ASan) to depend on one runtime DLL regardless of the runtime configuration. This simplifies project onboarding and supports more scenarios, particularly for projects statically linked (/MT, /MTd) to the C Runtimes. However, static configurations have a new dependency on the ASan runtime DLL. Summary of the changes: ASan now works with /MT or /MTd built DLLs when the host EXE was not compiled with ASan. This includes Windows services, COM components, and plugins. Configuring your project with ASan is now simpler, since your project doesn’t need to uniformly specify the same runtime configuration (/MT, /MTd, /MD, /MDd). ASan workflows and pipelines for /MT or /MTd built projects will need to ensure the ASan DLL (clang_rt.asan_dynamic-.dll) is available on PATH. The names of the ASan .lib files needed by the linker have changed (the linker normally takes care of this if not manually specifying lib names via /INFERASANLIBS) You cannot mix ASan-compiled binaries from previous versions of the MSVC Address Sanitizer (this is always true, but especially true in this case). Motivation and Effects When building a project, you must specify how you want to link to the C and C++ Runtime Libraries. Using the /MD option will link dynamically to the runtimes and have DLL dependencies provided by the Windows operating system (ex: ucrtbase.dll) and the VC++ Redistributable (ex: vcruntime140.dll, msvcp140.dll). This is a great default option to choose, as it allows you to take advantage of the latest available on the system and minimizes memory usage. The /MT option specifies that the runtime libraries will be statically linked (via libucrt.lib, libvcruntime.lib, libcpmt.lib, etc) in your program such that you have no VC++ DLL dependencies. This option is useful when dynamically linking complicates deployment and is most frequently used with projects like plugins or drivers. Prior to Visual Studio 2022 v17.7 Preview 3, MSVC Address Sanitizer followed the same methodology and treated itself as one of the runtime libraries. If /MD was specified, ASan would be available as a DLL (clang_rt.asan_dynamic-.dll). If /MT was specified, ASan would be linked into the EXE. ASan can only have one instance at a time, so DLLs that were statically linked would assume the EXE of the process was also built with ASan and would call into that EXE for support. This caused problems for any software that could not recompile the host EXE with ASan enabled: plugins, COM components, Windows services, etc. Here is an example reported on Developer Community. Additionally, since each runtime configuration had its own version of ASan, you could not mix components with different runtime configurations. As of Visual Studio v17.7 Preview 3, runtime configuration is no longer considered and there is one Address Sanitizer DLL per architecture. In addition to supporting more scenarios, this can also significantly simplify onboarding a complex project with ASan. A side effect is that projects statically linked with /MT or /MTd now have a dependency on the ASan runtime DLL. Link Time Changes (/INFERASANLIBS) When /fsanitize=address is passed to the compiler, /INFERASANLIBS will automatically be passed to the linker, which will take care of the link time requirements for Address Sanitizer. If […]

Read More

Learn Beneficial Methods Of Modern C++

Hello everyone, Yilmaz here, from LearnCPlusPlus.org. Our educational LearnCPlusPlus.org web page is growing thanks to the support of you. We have many new readers, and we keep adding new C++ posts every day. These are good to learn the features of modern C++ compilers. In this round-up of recent articles, we explain some features of modern C++ along with other beneficial methods for intermediate and professional developers. This week, we have C++ examples and an explanation about using non-copyable movable types in C++ templates. The rvalue references are important and we explain rvalue references to eliminate unnecessary copying in C++. C++11, C++17, and C++20 standards added to the richness of the language, and we explain one of these additions – explicit conversion operators. If you wonder what an explicit specifier is, we explain them in another post. C++11 introduced two new features: defaulted and deleted functions, we can use these two keywords to delete or to default methods in C++, and we explain this in the other two posts. Table of Contents Where can I learn C++ with a free C++ compiler? How to use modern C++ with C++ Builder? How to learn C++ for free using C++ Builder? What is new in C++ Builder CE? What might be next for C++ Builder? Where can I learn C++ with a free C++ compiler? If you don’t know anything about C++ or the C++ Builder IDE, don’t worry, we have a lot of great examples on the LearnCPlusPlus.org website and they’re all completely free. Just visit this site and copy and paste any examples there into a new Console, VCL, or FMX project, depending on the type of post. We keep adding more C and C++ posts with sample code. In today’s round-up of recent posts on LearnCPlusPlus.org, we have new articles with very simple examples that can be used with: The free version of C++ Builder 11 CE Community Edition or a professional version of C++ Builder  or free BCC32C C++ Compiler and BCC32X C++ Compiler or the free Dev-C++ Read the FAQ notes on the CE license and then simply fill out the form to download C++ Builder 11 CE. How to use modern C++ with C++ Builder? In C++, memory and CPU/GPU management are very important. Every declaration and usage of any items can cause a lot of heavy calculations, memory usage, and high CPU/GPU usage if used or manipulated unwisely. Using copy and move types in templates is very important when you develop a professional app. In the first post, we explain how you can use non-copyable movable types in C++ templates. https://learncplusplus.org/learn-how-to-use-non-copyable-movable-types-in-c-templates/ The rvalue references are a compound type like standard C++ references, which are referred to as lvalue references. New rvalue reference rules were set by the C++11 specifications. In many cases, data is copied that simply needs to be moved, that is, the original data holder need not retain the data. The rvalue reference can be used to distinguish cases that require copying versus cases that merely require moving data. In the next post, we explain how we use rvalue references to eliminate unnecessary copying in C++. https://learncplusplus.org/learn-how-to-eliminate-unnecessary-copying-in-c/ In modern C++, explicit-qualified conversion functions work in the same context as explicit-qualified constructors and produce diagnostics in the same contexts as constructors do. C++11, C++17, and C++20 standards have improvements in this explicit specifier. This is done to avoid situations when the compiler uncomplainingly accepts code […]

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