// Application to show a possible problem of Boost condition variables in // combination with a POSIX timer and signals #include #include #include #include "boost/thread/condition_variable.hpp" #include "boost/date_time/posix_time/posix_time.hpp" #include struct sigaction timerSigAction; struct sigaction oldSigAction; timer_t timer; int timerCount = 0; #define SIGNAL_IN_USE (SIGRTMIN) /* handler installed to handle signals generated by the timer */ static void timerHandler(int signo) { if (signo != SIGNAL_IN_USE) { return; } timerCount++; return; } /* restores signal handlers and removes timer */ static void stopTimer() { timer_delete(timer); sigaction(SIGNAL_IN_USE, &oldSigAction, NULL); } /* timer initializer */ static void startTimer() { struct sigevent signalEvent; struct itimerspec timerSpec; sigset_t blockedSignals; sigemptyset(&blockedSignals); timerSigAction.sa_handler = timerHandler; timerSigAction.sa_flags = SA_RESTART; timerSigAction.sa_mask = blockedSignals; if (sigaction(SIGNAL_IN_USE, &timerSigAction, &oldSigAction)) { return; } signalEvent.sigev_notify = SIGEV_SIGNAL; signalEvent.sigev_signo = SIGNAL_IN_USE; if (timer_create(CLOCK_REALTIME, &signalEvent, &timer)) { stopTimer(); // restore signal handler return; } timerSpec = (struct itimerspec){ {(time_t)0, 50000000L}, {(time_t)0, 50000000L} }; if (timer_settime(timer, 0, &timerSpec, NULL)) { stopTimer(); // clean up timer and restore signal handler return; } } void BoostConditionVar() { boost::mutex m; boost::unique_lock lk(m); boost::condition_variable cond; cond.timed_wait(lk, boost::posix_time::millisec(1000)); } void OwnConditionVar() { pthread_mutex_t m_mutex; pthread_cond_t m_cond; pthread_mutexattr_t mutexattr; pthread_mutexattr_init(&mutexattr); pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&m_mutex, &mutexattr); pthread_mutexattr_destroy(&mutexattr); pthread_condattr_t condattr; pthread_condattr_init(&condattr); pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); pthread_cond_init(&m_cond, &condattr); pthread_condattr_destroy(&condattr); struct timespec t1; clock_gettime(CLOCK_MONOTONIC, &t1); t1.tv_sec += 1; pthread_mutex_lock(&m_mutex); pthread_cond_timedwait(&m_cond, &m_mutex, &t1); pthread_mutex_destroy(&m_mutex); pthread_cond_destroy(&m_cond); } int kbhit() { struct timeval tv; fd_set fds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0 select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); return FD_ISSET(STDIN_FILENO, &fds); } int main(int argc, char *argv[]) { bool useSignals = false; bool useBoost = false; static struct option long_options[] = { {"signals", no_argument, 0, 's'}, {"boost", no_argument, 0, 'b'}, {0, 0, 0, 0 } }; int option_index = 0; int opt; while ((opt = getopt_long(argc, argv, "sb", long_options, &option_index)) != -1) { switch (opt) { case 's': fprintf(stderr, "Generating POSIX signals\n"); useSignals = 1; break; case 'b': fprintf(stderr, "Using Boost condition variables\n"); useBoost = 1; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-b] [-s] \n", argv[0]); fprintf(stderr, "-b --boost: use boost condition variable\n"); fprintf(stderr, "-s --signals: generate POSIX signals\n"); exit(EXIT_FAILURE); } } if(useSignals) { startTimer(); } printf("Press ENTER to stop\n"); sem_t sem; if (sem_init(&sem, 0, 1) == -1) { if(useSignals) { stopTimer(); } perror("sem_init"); exit(EXIT_FAILURE); } struct timespec t1; struct timespec t2; while(kbhit() == false) { if (useBoost) { BoostConditionVar(); } else { OwnConditionVar(); } boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); std::string output = to_simple_string(now); int retval1 = clock_gettime(CLOCK_REALTIME, &t1); int retval2 = clock_gettime(CLOCK_MONOTONIC, &t2); printf("%s %d %d.%9.9d %d %d.%9.9d %d\n", output.c_str(), retval1, t1.tv_sec, t1.tv_nsec, retval2, t2.tv_sec, t2.tv_nsec, timerCount); } if(useSignals) { stopTimer(); } }