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 <iostream> #include <thread> 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 << store_items << " + " << shop_items << std::endl; std::thread t1( transfer_items, 5, std::ref(store_items), std::ref(shop_items) ); std::thread t2( transfer_items, 2, std::ref(shop_items), std::ref(store_items) ); t1.join(); t2.join(); std::cout << store_items << " + " << shop_items << std::endl; system("pause"); } |
Note that, your problem may require different features of concurrency support library. You can find many useful modern and simple multi-thread examples in our LearnCPlusPlus.org.
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.
Design. Code. Compile. Deploy.
Start Free Trial
Free C++Builder Community Edition