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