2.4.10. age_mutex.cpp
#
2.4.10.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 <mutex>
9#include <thread>
10#include <chrono>
11#include <csignal>
12#include <sstream>
13
14namespace po = boost::program_options;
15
16// Interrupt signal handlers
17static bool stop_signal_called = false;
18void sig_int_handler(int){
19 stop_signal_called = true;
20}
21
22// Internal locking
23class SharedPrinter {
24 private:
25 std::mutex mtx;
26 public:
27 void print(std::string message) {
28 mtx.lock();
29 std::cout << message;
30 mtx.unlock();
31 }
32};
33
34// Use a scoped lock alternatively
35// class SharedPrinter {
36// private:
37// std::mutex mtx;
38// public:
39// void print(std::string message) {
40// std::lock_guard<std::mutex> scoped_lock(mtx);
41// std::cout << message;
42// }
43// };
44
45
46// worker function to print age
47void print_age(std::string name, int age, bool nice, SharedPrinter* printer) {
48
49 std::ostringstream message;
50 if (nice) {
51 // nice printing
52 if (age < 0) {
53 message << "From Thread #" << std::this_thread::get_id() << ": " << name << "'s age is unknown." << std::endl;
54 } else {
55 message << "From Thread #" << std::this_thread::get_id() << ": " << name << " is " << age << " years old." << std::endl;
56 }
57 } else {
58 // not nice printing
59 message << "Thread #" << std::this_thread::get_id() << ": " << std::endl << "Name = " << name << std::endl << "Age = " << age << std::endl;
60 }
61 while (not stop_signal_called) {
62 printer->print(message.str());
63 std::this_thread::sleep_for(std::chrono::seconds(1)); // Just don't go too fast
64 }
65}
66
67int UHD_SAFE_MAIN(int argc, char *argv[]) {
68 // Set main thread priority to highest
69 uhd::set_thread_priority_safe(1.0, true);
70
71 //variables to be set by po
72 std::string name;
73 int age;
74
75 //setup the program options
76 po::options_description desc("Allowed options");
77 desc.add_options()
78 ("help", "help message")
79 ("name,n", po::value<std::string>(&name)->default_value("This person"), "The person's name")
80 ("age,a", po::value<int>(&age)->default_value(-1), "The person's age")
81 ("nice-print", "Print out the info nicely")
82 ;
83
84 po::variables_map vm;
85 po::store(po::parse_command_line(argc, argv, desc), vm);
86 po::notify(vm);
87
88 //print the help message
89 if (vm.count("help")) {
90 std::cout << desc << std::endl;
91 return EXIT_SUCCESS;
92 }
93
94 std::signal(SIGINT, &sig_int_handler);
95
96 // Instantiate the SharedPrinter object
97 SharedPrinter printer;
98
99 // Spawn 10 worker threads
100 int num_threads = 10;
101 std::thread worker[num_threads];
102 for (int i=0; i<num_threads; i++) {
103 worker[i] = std::thread(&print_age, name, age, vm.count("nice-print"), &printer);
104 }
105
106 // Keep running until CTRL-C issued
107 while (not stop_signal_called) {
108 std::this_thread::sleep_for(std::chrono::milliseconds(1)); // sleep for 1ms to make sure can catch CTRL-C
109 }
110
111 // Join all worker threads
112 for (int i=0; i<num_threads; i++) {
113 if (worker[i].joinable()) worker[i].join();
114 }
115
116 std::cout << std::endl;
117 return EXIT_SUCCESS;
118}
2.4.10.2. Build#
Need to link the
uhd
,boost_program_options
libraries when compiling:g++ age_mutex.cpp -o age_mutex -luhd -lboost_program_options
2.4.10.3. Usage Example#
$ ./age_mutex --nice-print --name=Tom -a 25
Experiment
Run the example above to see what happens! Compare the results with those obtained running age_threads.cpp.
Change the code to use scoped lock instead. Compile and run the code to test.