栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Linux中的定时器在C [重复]

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux中的定时器在C [重复]

您要使用信号还是线程?

首先,设置信号处理程序或准备合适的线程函数;有关详细信息,请参见man 7
sigevent

接下来,使用创建一个合适的计时器

timer_create()
。有关详细信息,请参见man 2
timer_create

根据计时器触发时的操作,您可能希望将计时器设置为一次触发,或稍后再重复一次。您

timer_settime()
可以同时使用计时器和撤防计时器。有关详细信息,请参见man
2 timer_settime

在实际应用中,通常需要复用计时器。即使一个进程可以创建多个计时器,它们也是有限的资源。特别是超时计时器-这很简单-设置标志和/或向特定线程发送信号-
应该使用单个计时器,该计时器在下一次超时时触发,设置相关的超时标志,并可选地发送信号(使用空体处理程序)到所需线程以确保其被中断。(对于单线程进程,原始信号传递将中断阻止I
/ O调用。)考虑服务器,它对某些请求做出响应:在处理请求时,请求本身可能会有一分钟左右的超时时间可能需要连接超时,I / O超时等等。

现在,最初的问题很有趣,因为计时器在有效使用时功能强大。但是,示例程序基本上是胡说八道。您为什么不创建一个程序,该程序设置一个或多个计时器,每个计时器例如将一些内容输出到标准输出?请记住使用

write()
from等,
unistd.h
因为它们是异步信号安全的,而
printf()
from等
stdio.h
则不是。(如果信号处理程序使用非异步信号安全函数,则结果是不确定的。它通常可以工作,但完全不能保证;它和工作一样崩溃。测试是
不明确的 ,因为它是 不确定的 。)


编辑添加:这是复用超时的准系统示例。

(在法律允许的范围内,我将以下所示代码段的所有版权,相关权和邻接权专用于全球公共领域;请参阅CC0公共领域专用。换句话说,请随时以任何方式使用以下代码希望,只是不要怪我有任何问题。)

我使用了旧式的GCC原子内置函数,因此它应该是线程安全的。除了一些补充,它也应该适用于多线程代码。(您不能使用例如互斥锁,因为

pthread_mutex_lock()
这不是异步信号安全的方法。以原子方式操作超时状态应该可以工作,尽管如果在触发时禁用超时可能会留下一些竞争。)

#define _POSIX_C_SOURCE 200809L#include <unistd.h>#include <signal.h>#include <time.h>#include <errno.h>#define   TIMEOUTS       16#define   TIMEOUT_SIGNAL (SIGRTMIN+0)#define   TIMEOUT_USED   1#define   TIMEOUT_ARMED  2#define   TIMEOUT_PASSED 4static timer_t    timeout_timer;static volatile sig_atomic_t timeout_state[TIMEOUTS] = { 0 };static struct timespec       timeout_time[TIMEOUTS];static inline double timespec_diff(const struct timespec after, const struct timespec before){    return (double)(after.tv_sec - before.tv_sec)         + (double)(after.tv_nsec - before.tv_nsec) / 1000000000.0;}static inline void timespec_add(struct timespec *const to, const double seconds){    if (to && seconds > 0.0) {        long  s = (long)seconds;        long  ns = (long)(0.5 + 1000000000.0 * (seconds - (double)s));                if (ns < 0L) ns = 0L;        else        if (ns > 999999999L) ns = 999999999L;        to->tv_sec += (time_t)s;        to->tv_nsec += ns;        if (to->tv_nsec >= 1000000000L) { to->tv_nsec -= 1000000000L; to->tv_sec++;        }    }}static inline void timespec_set(struct timespec *const to, const double seconds){    if (to) {        if (seconds > 0.0) { const long  s = (long)seconds; long       ns = (long)(0.5 + 1000000000.0 * (seconds - (double)s)); if (ns < 0L)     ns = 0L; else if (ns > 999999999L)     ns = 999999999L; to->tv_sec = (time_t)s; to->tv_nsec = ns;        } else { to->tv_sec = (time_t)0; to->tv_nsec = 0L;        }    }}static inline int timeout_passed(const int timeout){    if (timeout >= 0 && timeout < TIMEOUTS) {        const int  state = __sync_or_and_fetch(&timeout_state[timeout], 0);                if (!(state & TIMEOUT_USED)) return -1;                if (!(state & TIMEOUT_ARMED)) return -1;                return (state & TIMEOUT_PASSED) ? 1 : 0;    } else {                return -1;    }}static inline int timeout_unset(const int timeout){    if (timeout >= 0 && timeout < TIMEOUTS) {                const int  state = __sync_fetch_and_and(&timeout_state[timeout], TIMEOUT_PASSED);                if (!(state & TIMEOUT_USED)) return -1;                if (!(state & TIMEOUT_ARMED)) return -1;                return (state & TIMEOUT_PASSED) ? 1 : 0;    } else {                return -1;    }}int timeout_set(const double seconds){    struct timespec   now, then;    struct itimerspec when;    double next;    int    timeout, i;        if (seconds <= 0.0)        return -1;        if (clock_gettime(CLOCK_REALTIME, &now))        return -1;        then = now;    timespec_add(&then, seconds);        for (timeout = 0; timeout < TIMEOUTS; timeout++)        if (!(__sync_fetch_and_or(&timeout_state[timeout], TIMEOUT_USED) & TIMEOUT_USED)) break;        if (timeout >= TIMEOUTS)        return -1;        __sync_and_and_fetch(&timeout_state[timeout], TIMEOUT_USED);        timeout_time[timeout] = then;        __sync_or_and_fetch(&timeout_state[timeout], TIMEOUT_ARMED);        next = seconds;    for (i = 0; i < TIMEOUTS; i++)        if ((__sync_fetch_and_or(&timeout_state[i], 0) & (TIMEOUT_USED | TIMEOUT_ARMED | TIMEOUT_PASSED)) == (TIMEOUT_USED | TIMEOUT_ARMED)) { const double secs = timespec_diff(timeout_time[i], now); if (secs >= 0.0 && secs < next)     next = secs;        }        timespec_set(&when.it_value, next);    when.it_interval.tv_sec = 0;    when.it_interval.tv_nsec = 0L;        if (timer_settime(timeout_timer, 0, &when, NULL)) {                __sync_and_and_fetch(&timeout_state[timeout], 0);        return -1;    }        return timeout;}static void timeout_signal_handler(int signum __attribute__((unused)), siginfo_t *info, void *context __attribute__((unused))){    struct timespec   now;    struct itimerspec when;    int    saved_errno, i;    double next;        if (!info || info->si_pre != SI_TIMER)        return;        saved_errno = errno;    if (clock_gettime(CLOCK_REALTIME, &now)) {        errno = saved_errno;        return;    }        next = -1.0;        for (i = 0; i < TIMEOUTS; i++)        if ((__sync_or_and_fetch(&timeout_state[i], 0) & (TIMEOUT_USED | TIMEOUT_ARMED | TIMEOUT_PASSED)) == (TIMEOUT_USED | TIMEOUT_ARMED)) { const double  seconds = timespec_diff(timeout_time[i], now); if (seconds <= 0.0) {          __sync_or_and_fetch(&timeout_state[i], TIMEOUT_PASSED); } else if (next <= 0.0 || seconds < next) {          next = seconds; }        }        timespec_set(&when.it_value, next);    when.it_interval.tv_sec = 0;    when.it_interval.tv_nsec = 0L;    timer_settime(timeout_timer, 0, &when, NULL);        errno = saved_errno;}int timeout_init(void){    struct sigaction  act;    struct sigevent   evt;    struct itimerspec arm;        sigemptyset(&act.sa_mask);    act.sa_sigaction = timeout_signal_handler;    act.sa_flags = SA_SIGINFO;    if (sigaction(TIMEOUT_SIGNAL, &act, NULL))        return errno;        evt.sigev_notify = SIGEV_SIGNAL;    evt.sigev_signo = TIMEOUT_SIGNAL;    evt.sigev_value.sival_ptr = NULL;    if (timer_create(CLOCK_REALTIME, &evt, &timeout_timer))        return errno;        arm.it_value.tv_sec = 0;    arm.it_value.tv_nsec = 0L;    arm.it_interval.tv_sec = 0;    arm.it_interval.tv_nsec = 0L;    if (timer_settime(timeout_timer, 0, &arm, NULL))        return errno;    return 0;}int timeout_done(void){    struct sigaction  act;    struct itimerspec arm;    int    errors = 0;        sigemptyset(&act.sa_mask);    act.sa_handler = SIG_IGN;    if (sigaction(TIMEOUT_SIGNAL, &act, NULL))        if (!errors) errors = errno;        arm.it_value.tv_sec = 0;    arm.it_value.tv_nsec = 0L;    arm.it_interval.tv_sec = 0;    arm.it_interval.tv_nsec = 0;    if (timer_settime(timeout_timer, 0, &arm, NULL))        if (!errors) errors = errno;        if (timer_delete(timeout_timer))        if (!errors) errors = errno;        if (errors)        errno = errors;        return errors;}

记住

rt
在编译时包括库,即用于
gcc -W -Wall *source*.c -lrt -o *binary*
编译。

这个想法是,主程序首先调用

timeout_init()
以安装所有必需的处理程序等,然后可以
timeout_done()
在退出之前(或在进入之后的子进程中
fork()
)调用deistall

要设置超时,请致电

timeout_set(seconds)
。返回值是超时描述符。当前,您可以使用来检查一个标志
timeout_passed()
,但是超时信号的传递也会中断任何阻塞的I
/ O调用。因此,您可以期望超时会中断任何阻塞的I / O调用。

如果您想要做的只是设置超时标志,则不能在信号处理程序中进行;请记住,在信号处理程序中,您仅限于异步信号安全功能。最简单的方法是使用一个单独的线程,该线程具有无限循环

sigwaitinfo()
TIMEOUT_SIGNAL
信号在所有其他线程中均被阻塞。这样,可以确保专用线程捕获信号,但同时,不限于异步信号安全功能。例如,它可以做更多的工作,甚至可以使用将信号发送到特定线程
pthread_kill()
。(只要该信号具有一个处理程序,即使是一个带有空主体的处理程序,它的传递都会中断该线程中任何阻塞的I
/ O调用。)

这是一个

main()
使用超时的简单示例。它很愚蠢,并且依赖于
fgets()
不重试(被信号中断时),但是它似乎可以工作。

#include <string.h>#include <stdio.h>int main(void){    char    buffer[1024], *line;    int t1, t2, warned1;    if (timeout_init()) {        fprintf(stderr, "timeout_init(): %s.n", strerror(errno));        return 1;    }    printf("You have five seconds to type something.n");    t1 = timeout_set(2.5); warned1 = 0;    t2 = timeout_set(5.0);    line = NULL;    while (1) {        if (timeout_passed(t1)) {  if (!warned1++)     printf("nTwo and a half seconds left, buddy.n");        }        if (timeout_passed(t2)) { printf("nAw, just forget it, then.n"); break;        }        line = fgets(buffer, sizeof buffer, stdin);        if (line) { printf("nOk, you typed: %sn", line); break;        }    }        timeout_unset(t1);    timeout_unset(t2);        if (timeout_done()) {        fprintf(stderr, "timeout_done(): %s.n", strerror(errno));        return 1;    }    return 0;}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/382829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号