c++ - sem_timedwait 与 CLOCK_MONOTONIC_RAW/CLOCK_MONOTONIC

标签 c++ c linux linux-kernel

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 的示例代码使用 CLOCK_REALTIME 作为 clock_gettime(struct timespec * timeout) 但这很容易受到系统时钟时间变化的影响,例如一些其他进程向后改变时间。

有没有sem_timedwait支持CLOCK_MONOTONIC时间源

下面是一些示例代码供引用。

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

简答:no .

但如果您不使用第 3 方库或 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;
}

然后使用它:

#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;
}

以上内容适用于广泛的 *nix 系统,包括 BSD 系列。如果您需要一种跨平台的方式来执行此操作,Windows 和 Apple 有更简单的机制来执行此操作。

希望对您有所帮助。

关于c++ - sem_timedwait 与 CLOCK_MONOTONIC_RAW/CLOCK_MONOTONIC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40698438/

相关文章:

c - 不同次数的 printf 调用的不同输出

C 使用 getopt_long()

linux - 嵌入式linux平台可以使用什么轻量级容器

linux - ip_len 设置为非常大的值

c++ - 客户端和服务器示例不工作

c++ - Win32 线程无明显原因死亡

c++ - 如何使用_mm_extract_epi8函数?

c++ - 如何将 MQL4 代码转换为 C++/Delphi DLL(复盘大师 API)?

C 将char数组(字符串)UTF8格式转换为CP1252(ASCII)格式

c - 如何等待非子进程退出