[英]sem_timedwait with CLOCK_MONOTONIC_RAW/CLOCK_MONOTONIC
The example code for int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
的示例代码uses CLOCK_REALTIME
as the time source from clock_gettime(struct timespec *timeout)
but this is susceptible to system clock time changes for example some other process changing time backwards.使用CLOCK_REALTIME
作为来自clock_gettime(struct timespec *timeout)
的时间源,但这很容易受到系统时钟时间变化的影响,例如一些其他进程向后改变时间。
Is there a support for sem_timedwait
to support CLOCK_MONOTONIC
time source是否支持sem_timedwait
支持CLOCK_MONOTONIC
时间源
below is some example code for reference.下面是一些示例代码供参考。
struct timespec ts;
sem_t sema;
sem_init(&sema, 0, 0)
int ret;
if ( -1 != (ret = clock_gettime(CLOCK_REALTIME, &ts))){
ts.tv_sec += 1;
return sem_timedwait(sema, &ts);
}
Is there a support for sem_timedwait to support CLOCK_MONOTONIC time source 是否支持sem_timedwait以支持CLOCK_MONOTONIC时间源
But you could implement one if you're not using a 3rd party library or C++11 and don't need cross-platform compatibility: 但是,如果您不使用第三方库或C ++ 11并且不需要跨平台兼容性,则可以实现一个:
#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. 以上工作适用于各种* nix系统,包括BSD系列。 If you need a cross platform way of doing this, Windows and Apple have simpler mechanisms to do this. 如果您需要跨平台的方式,Windows和Apple有更简单的机制来执行此操作。
Hope that can help. 希望能有所帮助。
Had the same problem with POSIX system, Based on C++0x has no semaphores? 与POSIX系统有同样的问题,基于C ++ 0x没有信号量? How to synchronize threads? 如何同步线程? and How do I deal with the system clock changing while waiting on a std::condition_variable? 如何在等待std :: condition_variable时处理系统时钟更改? and Halûk Uçar answer 和HalûkUçar回答
#include <stdio.h>
#include <thread>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
class semaphore
{
private:
pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_condattr_t m_attr;
pthread_cond_t m_cond;
unsigned long count_ = 0;
public :
void init_sem()
{
int result = 0;
result = pthread_condattr_init(&m_attr);
result = pthread_condattr_setclock(&m_attr, CLOCK_MONOTONIC);
result = pthread_cond_init(&m_cond, &m_attr);
}
void notify() {
pthread_mutex_lock(&m_mutex);
++count_;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
void wait() {
pthread_mutex_lock(&m_mutex);
while (!count_) // Handle spurious wake-ups.
{
pthread_cond_wait(&m_cond, &m_mutex);
}
--count_;
pthread_mutex_unlock(&m_mutex);
}
void wait_for(int sec)
{
int rc = 0;
pthread_mutex_lock(&m_mutex);
if (!count_)
{
timespec tsTimeout;
clock_gettime(CLOCK_MONOTONIC, &tsTimeout);
// update time calculation to your specific case
tsTimeout.tv_sec += time;
// Handle spurious wake-ups.
while (!count_ && (rc == 0))
{
rc = pthread_cond_timedwait(&m_cond, &m_mutex, &tsTimeout);
}
}
if (rc == 0)
{
printf("success\n");
--count_;
}
else if (rc == ETIMEDOUT)
{
printf("timeout\n");
}
else
{
printf("error\n");
}
pthread_mutex_unlock(&m_mutex);
}
bool destroy()
{
return ((pthread_cond_destroy(&m_cond) == 0)
&& (pthread_mutex_destroy(&m_mutex) == 0)
&& (pthread_condattr_destroy(&m_attr)==0)) ? true : false;
}
};
You can implement your own semaphore routines by using 您可以使用实现自己的信号量例程
Of course semaphore creation and deletion will include malloc and free, where you alloc a struct with all parameters (mutex, condition, ... ) needed for your semaphore implementation. 当然,信号量的创建和删除将包括malloc和free,你可以在其中分配一个包含信号量实现所需的所有参数(互斥,条件......)的结构。
If anyone stumbles across this in the future:如果将来有人偶然发现这一点:
glibc has now implemented this (since version 2.30): glibc 现在已经实现了这个(从 2.30 版开始):
https://www.gnu.org/software/libc/manual/html_node/Waiting-with-Explicit-Clocks.html https://www.gnu.org/software/libc/manual/html_node/Waiting-with-Explicit-Clocks.html
you can use sem_clockwait with CLOCK_MONOTONIC.您可以将 sem_clockwait 与 CLOCK_MONOTONIC 一起使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.