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.