From d81c65b1d2ba86c0c4424062f1b157a35da67980 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Fri, 1 Apr 2022 10:13:56 -0400 Subject: [PATCH] [cpp] Add multithreaded project + Add example for race condition problem / solution --- cpp/CMakeLists.txt | 3 +- cpp/multithreading/CMakeLists.txt | 18 ++++++ .../race-condition/CMakeLists.txt | 22 +++++++ cpp/multithreading/race-condition/driver.cpp | 64 +++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 cpp/multithreading/race-condition/driver.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 6190522..78c07d7 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -25,4 +25,5 @@ add_subdirectory(cmake-example) add_subdirectory(cryptography) add_subdirectory(datastructs) add_subdirectory(graphics) -add_subdirectory(patterns) +add_subdirectory(multithreading) +add_subdirectory(patterns) \ No newline at end of file diff --git a/cpp/multithreading/CMakeLists.txt b/cpp/multithreading/CMakeLists.txt index e69de29..ac834e4 100644 --- a/cpp/multithreading/CMakeLists.txt +++ b/cpp/multithreading/CMakeLists.txt @@ -0,0 +1,18 @@ +################################################################################ +## Author: Shaun Reed ## +## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## About: A root project for practicing C++ multithreading ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ + +cmake_minimum_required(VERSION 3.16) + +project( + #[[NAME]] Multithreading + VERSION 1.0 + DESCRIPTION "Practice with multithreaded programming in C++" + LANGUAGES CXX +) + +add_subdirectory(race-condition) diff --git a/cpp/multithreading/race-condition/CMakeLists.txt b/cpp/multithreading/race-condition/CMakeLists.txt index e69de29..4c79652 100644 --- a/cpp/multithreading/race-condition/CMakeLists.txt +++ b/cpp/multithreading/race-condition/CMakeLists.txt @@ -0,0 +1,22 @@ +################################################################################ +## Author: Shaun Reed ## +## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## About: An example and solution for race conditions in C++ ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ + +cmake_minimum_required(VERSION 3.16) + +project( + #[[NAME]] RaceCondition + VERSION 1.0 + DESCRIPTION "Example and solution for race conditions" + LANGUAGES CXX +) + +add_executable( + multithread-race-condition driver.cpp +) + +target_link_libraries(multithread-race-condition pthread) diff --git a/cpp/multithreading/race-condition/driver.cpp b/cpp/multithreading/race-condition/driver.cpp new file mode 100644 index 0000000..4bb3988 --- /dev/null +++ b/cpp/multithreading/race-condition/driver.cpp @@ -0,0 +1,64 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## About: An example of a race condition problem and solution ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +################################################################################ +*/ + +#include +#include +#include +#include + +void problem() { + std::vector threads; + const uint8_t thread_count = 5; + // With no mutex lock, the final value will vary in the range 1000000-5000000 + // + Threads will modify x simultaneously, so some iterations will be lost + // + x will have same initial value entering this loop on different threads + uint32_t x = 0; + for (uint8_t i = 0; i < thread_count; i++) { + threads.emplace_back([&x](){ + for (uint32_t i = 0; i < 1000000; i++) { + x = x + 1; + }; + }); + } + // Ensure the function doesn't continue until all threads are finished + // + There's no issue here, the issue is in how `x` is accessed above + for (auto &thread : threads) thread.join(); + std::cout << x << std::endl; +} + +// Create mutex lock to prevent threads from modifying same value simultaneously +static std::mutex mtx; +void solution() { + std::vector threads; + const uint8_t thread_count = 5; + uint32_t x = 0; + for (uint8_t i = 0; i < thread_count; i++) { + threads.emplace_back([&x](){ + // The first thread that arrives here will 'lock' other threads from passing + // + Once first thread finishes, the next thread will resume + // + This process repeats until all threads finish + std::lock_guard lock(mtx); + for (uint32_t i = 0; i < 1000000; i++) { + x = x + 1; + }; + }); + } + // Ensure the function doesn't continue until all threads are finished + for (auto &thread : threads) thread.join(); + std::cout << x << std::endl; +} + +int main(const int argc, const char * argv[]) { + // Result will vary from 1000000-5000000 + problem(); + + // Result will always be 5000000 + solution(); + return 0; +}