2.4.12. count_atomic.cpp
#
2.4.12.1. Source code#
1// University of Florida EEL6528
2// Tan F. Wong
3// Jan 14, 2021
4
5#include <uhd/utils/safe_main.hpp>
6#include <uhd/utils/thread.hpp>
7#include <boost/program_options.hpp>
8#include <atomic>
9#include <mutex>
10#include <thread>
11#include <chrono>
12#include <csignal>
13#include <sstream>
14
15namespace po = boost::program_options;
16
17// Interrupt signal handlers
18static bool stop_signal_called = false;
19void sig_int_handler(int) {
20 stop_signal_called = true;
21}
22
23// Internal locking
24class SharedPrinter {
25 private:
26 std::mutex mtx;
27 public:
28 void print(std::string message) {
29 mtx.lock();
30 std::cout << message;
31 mtx.unlock();
32 }
33};
34
35// worker function that waits for its turn and then increments count
36void wait_and_count(int id, int n, std::atomic<unsigned long>& count, SharedPrinter& printer) {
37 while (not stop_signal_called) {
38 if ((count.load()/10)%n == id) {
39 // It is this thread's turn
40 std::ostringstream message;
41 message << "Thread #" << id << " increments count to " << ++count << std::endl;
42 printer.print(message.str());
43 std::this_thread::sleep_for(std::chrono::seconds(1)); // Just don't go too fast
44 } else {
45 // Not this thread's turn
46 std::this_thread::yield();
47 }
48 }
49}
50
51int UHD_SAFE_MAIN(int argc, char *argv[]) {
52 // Set main thread priority to highest
53 uhd::set_thread_priority_safe(1.0, true);
54
55 //variables to be set by po
56 int num_threads;
57
58 //setup the program options
59 po::options_description desc("Allowed options");
60 desc.add_options()
61 ("help", "help message")
62 ("num-threads,n", po::value<int>(&num_threads)->default_value(10), "Number of threads")
63 ;
64
65 po::variables_map vm;
66 po::store(po::parse_command_line(argc, argv, desc), vm);
67 po::notify(vm);
68
69 //print the help message
70 if (vm.count("help")) {
71 std::cout << desc << std::endl;
72 return EXIT_SUCCESS;
73 }
74
75 std::signal(SIGINT, &sig_int_handler);
76
77 // Instantiate the SharedPrinter object
78 SharedPrinter printer;
79
80 // Initialize atomic varaible storing the count
81 std::atomic<unsigned long> count(0);
82
83 // Spawn num_threads worker threads
84 std::thread worker[num_threads];
85 for (int i=0; i<num_threads; i++) {
86 worker[i] = std::thread(&wait_and_count, i, num_threads, std::ref(count), std::ref(printer));
87 }
88
89 // Keep running until CTRL-C issued
90 while (not stop_signal_called) {
91 std::this_thread::yield(); // This is more CPU efficient
92 }
93
94 // Join all worker threads
95 for (int i=0; i<num_threads; i++) {
96 if (worker[i].joinable()) worker[i].join();
97 }
98
99 std::cout << std::endl;
100 return EXIT_SUCCESS;
101}
Experiment
Study the source code . Compile and run it. Can you explain what the code does?
Why do we still need to use the mutexed
SharedPrinter
object here?Note the use of
std::this_thread::yield()
and the way of passing references in the function inside thestd::thread
constructor.