To run
g++ --std=c++11 -g -pthread [source-code-file]
Summary:
We spawn one thread for each character we wish to print and force all spawned threads to sleep with a condition variable. With the go() function all threads are woken up. Each thread has two parameters: the character it is meant to print and a value which forces synchronization among the threads so that the threads execute in a specific order. The synchronization value is the test condition for a while loop whose body forces the thread to go back to sleep, and the test evaluates to false when this synchronization value is equal to a global counter. Once a thread exits this while block, it prints its character, increments the global counter, and wakes up all other threads waiting on the condition variable.
A few notes:
- The condition variable is necessary to stop threads from executing as soon as they are spawned. It is the cleanest way to synchronize execution of code among multiple threads here.
- The global counter doesn’t have to be atomic but I’d rather just use better practices and not have to think about whether or not I could technically get away with a synchronization variable whose operations aren’t atomic.
- Forcing all threads to sleep and then waking them all up with the go() function is not unnecessary. If I allowed the threads to run as they were spawned, it’s possible that the thread printing the first character could be spawned and run to completion before any other thread is spawned. Then there would be nothing to wake up the second thread (as the first thread would have called condition_variable::notify_all() before the second thread went to sleep) and the program would hang indefinitely.
#include<iostream> #include<thread> #include<atomic> #include<condition_variable> #include<vector> using namespace std; atomic<int> counter(0); mutex mtx; condition_variable cv; void printCharacter(char c, int i) { unique_lock<mutex> lck(mtx); do { cv.wait(lck); } while (i != counter); cout << c; counter++; cv.notify_all(); return; } void go() { cv.notify_all(); } int main(void) { string message = "Hello, World!\n"; vector<thread> threads(message.size()); for(unsigned i = 0; i < threads.size(); i++) { threads.at(i) = thread(printCharacter, message.at(i), i); } go(); for(auto& th : threads) { th.join(); } return 0; }