2.4.14. age_fifo.cpp#

2.4.14.1. Source code#

  1// University of Florida EEL6528
  2// Tan F. Wong
  3// Jan 17, 2021
  4
  5#include <uhd/utils/safe_main.hpp>
  6#include <uhd/utils/thread.hpp>
  7#include <boost/program_options.hpp>
  8#include <thread>
  9#include <csignal>
 10#include <sstream>
 11#include "queue.hpp"
 12
 13namespace po = boost::program_options;
 14
 15// Interrupt signal handlers
 16static bool stop_signal_called = false;
 17void sig_int_handler(int){
 18    stop_signal_called = true;
 19}
 20
 21// worker function to generate age message and push it to FIFO
 22void print_age(std::string name, int age, bool nice, MutexFIFO<std::string>& fifo) {
 23
 24    // Set thread priority to highest
 25    uhd::set_thread_priority_safe(1.0, true);
 26    std::ostringstream message;
 27    if (nice) {
 28        // nice printing
 29        if (age < 0) {
 30            message << "Main thread popped message from Thread #" << std::this_thread::get_id() << ": " << name <<  "'s age is unknown." << std::endl;
 31        } else {
 32            message << "Main thread popped message from Thread #" << std::this_thread::get_id() << ": " << name << " is " << age << " years old." << std::endl;
 33        }
 34    } else {
 35        // not nice printing
 36        message << "Main thread popped message from Thread #" <<  std::this_thread::get_id() << ": " << std::endl << "Name = " << name << std::endl << "Age = " << age << std::endl;
 37    }
 38    while (not stop_signal_called) {
 39        fifo.push(message.str());
 40        std::this_thread::sleep_for(std::chrono::seconds(1)); // Just don't go too fast
 41    }
 42}
 43
 44int UHD_SAFE_MAIN(int argc, char *argv[]){
 45
 46    // Set main thread priority to highest
 47    uhd::set_thread_priority_safe(1.0, true);
 48 
 49    //variables to be set by po
 50    std::string name;
 51    int age;
 52 
 53    //setup the program options
 54    po::options_description desc("Allowed options");
 55    desc.add_options()
 56        ("help", "help message")
 57        ("name,n", po::value<std::string>(&name)->default_value("This person"), "The person's name")
 58        ("age,a", po::value<int>(&age)->default_value(-1), "The person's age")
 59        ("nice-print", "Print out the info nicely")
 60    ;
 61 
 62    po::variables_map vm;
 63    po::store(po::parse_command_line(argc, argv, desc), vm);
 64    po::notify(vm);
 65 
 66    //print the help message
 67    if (vm.count("help")){
 68        std::cout << desc << std::endl;
 69        return EXIT_SUCCESS;
 70    }
 71
 72    std::signal(SIGINT, &sig_int_handler);
 73
 74    // Construct FIFO to hold all messages
 75    MutexFIFO<std::string> fifo;
 76
 77    // Spawn 10 worker threads
 78    int num_threads = 10;
 79    std::thread worker[num_threads];
 80    for (int i=0; i<num_threads; i++) {
 81        worker[i] = std::thread(&print_age, name, age, vm.count("nice-print"), std::ref(fifo));
 82    }
 83    
 84	std::string message;
 85	 
 86    // Keep running until CTRL-C issued
 87    while (not stop_signal_called) {
 88        if (fifo.pop(message)) 
 89            std::cout << message << " (" << fifo.size() << " messages left in FIFO)" << std::endl;
 90        else
 91            std::cout << " FIFO is empty!" << std::endl;
 92        // The sleep_for time here determines the service rate 
 93        std::this_thread::sleep_for(std::chrono::milliseconds(80)); 
 94    }
 95
 96    // Join all  worker threads
 97    for (int i=0; i<10; i++) {
 98        if (worker[i].joinable()) worker[i].join();
 99    }
100
101    std::cout << std::endl;
102    return EXIT_SUCCESS;
103}
  • Ten worker threads push messages to the FIFO queue. Each thread pushes one message into the FIFO queue each second. Hence, the total arrival rate is 10 messages per second.

  • The main thread pops messages out of the FIFO queue. The service rate is determined by the sleep_for time on line 93.

Experiment

  1. Study the source code . Compile and run it. What results do you observe?

  2. Why don’t we need to use the mutexed SharedPrinter object here?

  3. Vary the sleep_for time on line 93 to see its effects on the queue size.