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

  1. Run the example above to see what happens! Compare the results with those obtained running age_threads.cpp.

  2. Change the code to use scoped lock instead. Compile and run the code to test.