Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Common Pitfalls in Concurrent Programming | Concurrency Foundations
Quizzes & Challenges
Quizzes
Challenges
/
C++ Concurrency and Multithreading

bookCommon Pitfalls in Concurrent Programming

Concurrency in C++ brings increased performance and responsiveness, but it also introduces several critical pitfalls that you must understand to write safe and reliable code. The three most common issues you will face are race conditions, deadlocks, and data corruption. These problems can be subtle, hard to detect, and may only appear under specific timing scenarios, making them particularly dangerous. Understanding these pitfalls is essential as you begin designing and debugging concurrent programs.

Race Condition

A race condition occurs when two or more threads access shared data concurrently, and the final outcome depends on the timing of their execution. Consider this C++ snippet:

main.cpp

main.cpp

copy
123456789101112131415161718192021
#include <iostream> #include <thread> int counter = 0; void increment() { for (int i = 0; i < 40000; ++i) ++counter; } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Final counter value: " << counter << std::endl; }

If both threads call increment() at the same time, the updates to counter can overlap, resulting in lost increments.

Deadlocks

Deadlocks happen when two or more threads are each waiting for the other to release a resource, causing all of them to stop progressing. Here is a simple illustration:

main.cpp

main.cpp

copy
1234567891011121314151617181920212223242526272829303132
#include <iostream> #include <thread> #include <mutex> std::mutex m1, m2; void taskA() { std::lock_guard<std::mutex> lock1(m1); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock2(m2); std::cout << "Task A completed\n"; } void taskB() { std::lock_guard<std::mutex> lock1(m2); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock2(m1); std::cout << "Task B completed\n"; } int main() { std::thread t1(taskA); std::thread t2(taskB); t1.join(); t2.join(); std::cout << "Program finished\n"; }

If taskA locks m1 and waits for m2, while taskB locks m2 and waits for m1, both threads become stuck — a deadlock occurs.

Data Corruption

This issue happens when shared data structures, such as containers, are accessed or modified by multiple threads at once. Without mechanisms like mutexes or locks, their internal state can be damaged, leading to crashes or inconsistent outcomes.

main.cpp

main.cpp

copy
12345678910111213141516171819202122
#include <iostream> #include <vector> #include <thread> std::vector<int> data; void addData(int value) { for (int i = 0; i < 1000; ++i) data.push_back(value); } int main() { std::thread t1(addData, 1); std::thread t2(addData, 2); t1.join(); t2.join(); std::cout << "Data size: " << data.size() << std::endl; }

If both threads call push_back at the same time, the internal structure of the vector can become corrupted, leading to crashes or unexpected results.

question mark

Which of the following scenarios is most likely to result in a race condition or a deadlock?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 1. Розділ 3

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Suggested prompts:

Can you explain how to prevent race conditions in C++?

What are some strategies to avoid deadlocks in concurrent programs?

How can I safely share data between threads in C++?

bookCommon Pitfalls in Concurrent Programming

Свайпніть щоб показати меню

Concurrency in C++ brings increased performance and responsiveness, but it also introduces several critical pitfalls that you must understand to write safe and reliable code. The three most common issues you will face are race conditions, deadlocks, and data corruption. These problems can be subtle, hard to detect, and may only appear under specific timing scenarios, making them particularly dangerous. Understanding these pitfalls is essential as you begin designing and debugging concurrent programs.

Race Condition

A race condition occurs when two or more threads access shared data concurrently, and the final outcome depends on the timing of their execution. Consider this C++ snippet:

main.cpp

main.cpp

copy
123456789101112131415161718192021
#include <iostream> #include <thread> int counter = 0; void increment() { for (int i = 0; i < 40000; ++i) ++counter; } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Final counter value: " << counter << std::endl; }

If both threads call increment() at the same time, the updates to counter can overlap, resulting in lost increments.

Deadlocks

Deadlocks happen when two or more threads are each waiting for the other to release a resource, causing all of them to stop progressing. Here is a simple illustration:

main.cpp

main.cpp

copy
1234567891011121314151617181920212223242526272829303132
#include <iostream> #include <thread> #include <mutex> std::mutex m1, m2; void taskA() { std::lock_guard<std::mutex> lock1(m1); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock2(m2); std::cout << "Task A completed\n"; } void taskB() { std::lock_guard<std::mutex> lock1(m2); std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock2(m1); std::cout << "Task B completed\n"; } int main() { std::thread t1(taskA); std::thread t2(taskB); t1.join(); t2.join(); std::cout << "Program finished\n"; }

If taskA locks m1 and waits for m2, while taskB locks m2 and waits for m1, both threads become stuck — a deadlock occurs.

Data Corruption

This issue happens when shared data structures, such as containers, are accessed or modified by multiple threads at once. Without mechanisms like mutexes or locks, their internal state can be damaged, leading to crashes or inconsistent outcomes.

main.cpp

main.cpp

copy
12345678910111213141516171819202122
#include <iostream> #include <vector> #include <thread> std::vector<int> data; void addData(int value) { for (int i = 0; i < 1000; ++i) data.push_back(value); } int main() { std::thread t1(addData, 1); std::thread t2(addData, 2); t1.join(); t2.join(); std::cout << "Data size: " << data.size() << std::endl; }

If both threads call push_back at the same time, the internal structure of the vector can become corrupted, leading to crashes or unexpected results.

question mark

Which of the following scenarios is most likely to result in a race condition or a deadlock?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 1. Розділ 3
some-alt