'c++ std::atomic concurrency printing
Hello everyone I have a code for threads to print their number and number that they are counting:
void print_num_n_times(std::uintmax_t thread_num, std::uintmax_t num_times_to_print = 100)
{
static std::atomic_bool is_printing{ false };
std::uintmax_t i = 0;
while (i < num_times_to_print)
{
//if the thread is not acquired.
while (is_printing.load());
//if the thread previous value was false (maybe another thread was intterupting.
if (!is_printing.exchange(true)) {
std::cout << "Output from thread " << thread_num << " Value: " << i + 1 << '\n';
is_printing.exchange(false);
i++;
}
}
}
and this is the only solution I have found for multiple threads to print nicely like this (2 threads count to 5):
Output from thread 2 Value: 1
Output from thread 2 Value: 2
Output from thread 2 Value: 3
Output from thread 2 Value: 4
Output from thread 2 Value: 5
Output from thread 1 Value: 1
Output from thread 1 Value: 2
Output from thread 1 Value: 3
Output from thread 1 Value: 4
Output from thread 1 Value: 5
Is there a better solution, because it's slow and I feel like there could be a better solution. Any help would be appreciated!
Solution 1:[1]
Here's a simplistic version of your code using a std::mutex and std::lock_guards to demonstrate one-shot threads with no other synchronization than using said mutex. In real situations you'd often use a std::condition_variable and a std::unique_lock to signal longer running threads that it's time to do some work.
#include <cstdint>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
void print_num_n_times(std::mutex& mtx, std::uintmax_t thread_num,
std::uintmax_t num_times_to_print)
{
std::lock_guard<std::mutex> lock(mtx); // wait here until acquiring the mutex lock
// this section will only be run by one thread (having locked the mutex) at a time
for (decltype(num_times_to_print) i = 0; i < num_times_to_print; ++i) {
std::cout << "Output from thread " << thread_num << " Value: " << i + 1 << '\n';
}
} // when `lock` goes out of scope, the mutex lock is released
// An auto joining thread for C++11, in C++20, use std::jthread
struct jthread : std::thread {
using std::thread::operator=;
~jthread() { if(joinable()) join(); }
};
int main() {
std::mutex mtx; // a mutex to use by all threads
std::vector<jthread> threads(3); // create 3 jthreads to run `print_num_n_times`
std::lock_guard<std::mutex> lock(mtx); // lock while starting all threads
// start the threads (while locking the mutex)
for (size_t i = 0; i < threads.size(); ++i) {
threads[i] = std::thread(print_num_n_times, std::ref(mtx), i + 1, 5);
}
} // 1. the lock_guard goes out of scope - the mutex is released
// 2. threads start acquiring the mutex lock (in an indeterminate order)
// and
// 2. the vector goes out of scope and its destructor is called
// 3. the jthreads in the vector all join()s their threads in their destructors
// 4. finally the mutex is destroyed
Possible output:
Output from thread 3 Value: 1
Output from thread 3 Value: 2
Output from thread 3 Value: 3
Output from thread 3 Value: 4
Output from thread 3 Value: 5
Output from thread 1 Value: 1
Output from thread 1 Value: 2
Output from thread 1 Value: 3
Output from thread 1 Value: 4
Output from thread 1 Value: 5
Output from thread 2 Value: 1
Output from thread 2 Value: 2
Output from thread 2 Value: 3
Output from thread 2 Value: 4
Output from thread 2 Value: 5
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ted Lyngmo |
