Is there a support for sem_timedwait to support CLOCK_MONOTONIC time source
Short answer: no.
But you could implement one if you're not using a 3rd party library or C++11 and don't need cross-platform compatibility:
#include <cstring> // memset
#include <ctime> // DEV_NOTE: some systems might need -lrt
#include <csignal> // DEV_NOTE: csignal contains a reference to CLOCK_MONOTONIC
#include <semaphore.h>
#if !defined(CLOCK_MONOTONIC)
#error CLOCK_MONOTONIC is not defined
#endif
typedef struct timespec tick_t;
static tick_t monotonic_tick()
{
tick_t tmp;
if (clock_gettime(CLOCK_MONOTONIC, &tmp) != 0) {
std::memset(&tmp, 0, sizeof(tick_t));
// error, throw std::exception(std::strerror(errno))
}
return tmp;
}
static double elapsed_us(tick_t init, tick_t end)
{
return ((end.tv_sec - init.tv_sec) * 1000000) + (static_cast<double>((end.tv_nsec - init.tv_nsec)) / 1000);
}
static double elapsed_ms(tick_t init)
{
return (elapsed_us(init, monotonic_tick()) / 1000);
}
static int sem_timed_wait(sem_t& sem, unsigned long timeout_ms)
{
if (timeout_ms == 0) {
if (sem_trywait(&sem) == 0) {
return 0;
}
} else {
tick_t start = monotonic_tick();
do {
if (sem_trywait(&sem) == 0) {
return 0;
}
} while (elapsed_ms(start) <= timeout_ms);
}
return -1;
}
Then to use it:
#include <iostream>
#include <pthread.h>
void* thread_fn(void* val)
{
sem_t* sem = static_cast<sem_t*>(val);
std::cout << std::endl << pthread_self() << " thread started" << std::endl;
if (sem_timed_wait(*sem, 1000) == 0) {
std::cout << std::endl << pthread_self() << " got it, sleeping 2 seconds..." << std::endl;
sleep(2); // sleep 2 seconds
std::cout << pthread_self() << " returning..." << std::endl;
// don't forget to release since we acquired the lock
sem_post(sem);
} else {
std::cout << pthread_self() << " timeout" << std::endl;
}
std::cout << pthread_self() << " thread returning" << std::endl;
return NULL;
}
int main(int argc, char* argv[])
{
sem_t sem;
pthread_t t1, t2;
sem_init(&sem, 0, 1); // binary semaphore
std::cout << "Creating..." << std::endl;
pthread_create(&t1, NULL, thread_fn, static_cast<void*>(&sem));
pthread_create(&t2, NULL, thread_fn, static_cast<void*>(&sem));
std::cout << "Joining..." << std::endl;
pthread_join(t1, NULL);
pthread_join(t2, NULL);
std::cout << "Leaving..." << std::endl;
return 0;
}
The above works on a wide array of *nix systems to include the BSD line. If you need a cross platform way of doing this, Windows and Apple have simpler mechanisms to do this.
Hope that can help.