Last active
November 7, 2019 06:51
-
-
Save DmitrySoshnikov/4b89bf2e67a72258ab709c97cef4009d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ------------------------------------------- | |
* Thread-safe vs. Non-thread-safe. Mutex. | |
* ------------------------------------------- | |
* | |
* Some resources (like global `cout` stream) have to be guarded | |
* in order to be thread-safe. | |
* | |
* The simplest way to guard is to use a mutex: | |
* | |
* mu.lock(); | |
* | |
* // do the critical section job | |
* | |
* mu.unlock(); | |
* | |
* Alternatively one case use std::lock_guard with RAII, | |
* which unlocks the mutex automatically, when the guard | |
* goes out of scope: | |
* | |
* lock_guard<mutex> guard(mu); | |
* | |
* In the example below we print rows of the array. | |
* Each thread is assigned to print its row. The first | |
* three threads operate on a non-thread-safe code, | |
* accessing randomly `cout` resource. The last three | |
* threads operate on the guarded code. | |
* | |
* by Dmitry Soshnikov <[email protected]> | |
* MIT Style License, 2019 | |
*/ | |
#include <iostream> | |
#include <thread> | |
#include <mutex> | |
using namespace std; | |
static int values[3][10] = { | |
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, | |
{ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, | |
{100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}, | |
}; | |
static mutex mu; | |
void nonThreadSafe(int row) { | |
for (int i = 0; i < 10; i++) { | |
cout << values[row][i] << ", "; | |
} | |
cout << "\n"; | |
} | |
void threadSafe(int row) { | |
// Note: RAII, instead of mu.lock()/mu.unlock() | |
// when `guard` goes out of scope, `mu` is unlocked. | |
lock_guard<mutex> guard(mu); | |
for (int i = 0; i < 10; i++) { | |
cout << values[row][i] << ", "; | |
} | |
cout << "\n"; | |
} | |
int main(int argc, char const *argv[]) { | |
cout << "\n----------- Non-thread-safe -------------\n\n"; | |
thread t1(nonThreadSafe, 0); | |
thread t2(nonThreadSafe, 1); | |
thread t3(nonThreadSafe, 2); | |
t1.join(); // main thread waits for t1 | |
t2.detach(); // main thread doesn't wait for t2 (t2 is daemon) | |
t3.join(); // waits for t3 | |
mu.lock(); | |
cout << "\n----------- Thread-safe -------------\n\n"; | |
mu.unlock(); | |
thread t5(threadSafe, 0); | |
thread t6(threadSafe, 1); | |
thread t7(threadSafe, 2); | |
t5.join(); | |
t6.join(); | |
t7.join(); | |
return 0; | |
} | |
/* | |
Results: | |
Note: the non-thread-safe results may depend on specific machine | |
and the thread scheduler. On my execution they are: | |
----------- Non-thread-safe ------------- | |
1, 2, 3, 104, , 5, 6100, , 200, 300, 20400, 30, 40, 50, 60, , 500, 70, 600807, 90, , 1008, 9, , 10, | |
700, | |
, 800, 900, 1000, | |
----------- Thread-safe ------------- | |
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, | |
10, 20, 30, 40, 50, 60, 70, 80, 90, 100, | |
100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
save -> safe