From 5598552b22b9b648b626e32ab2ead51e6cdc5fae Mon Sep 17 00:00:00 2001 From: lzy Date: Mon, 27 May 2024 17:53:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86anytimer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- C16-并发/C16-并发.md | 1 - C16-并发/parallel/signal/anytimer/anytimer.c | 202 +++++++++++++++++++ C16-并发/parallel/signal/anytimer/anytimer.h | 12 +- C16-并发/parallel/signal/anytimer/main.c | 18 +- 4 files changed, 230 insertions(+), 3 deletions(-) diff --git a/C16-并发/C16-并发.md b/C16-并发/C16-并发.md index 0e6185d..aa41a07 100644 --- a/C16-并发/C16-并发.md +++ b/C16-并发/C16-并发.md @@ -146,7 +146,6 @@ pthread_kill(pthread_self(), SIGINT); // 多线程等价 * * @eg: 使用单一计时器,构造一组函数,实现任意数量的定时器 * 用到 alarm 或 setitimer - * TODO * * 返回值:成功返回0,失败返回非零 */ diff --git a/C16-并发/parallel/signal/anytimer/anytimer.c b/C16-并发/parallel/signal/anytimer/anytimer.c index e69de29..36d7373 100644 --- a/C16-并发/parallel/signal/anytimer/anytimer.c +++ b/C16-并发/parallel/signal/anytimer/anytimer.c @@ -0,0 +1,202 @@ +/******************************************************************** + * @file anytimer.c + * @brief + * 单一定时器实现任意数量的定时器。 + * @author lzy (lllzzzyyy@buaa.edu.cn) + * @url https://lzyyyyyy.fun + * + * @date 2024-05-27 + * + ********************************************************************/ + +#include "anytimer.h" +#include +#include +#include +#include +#include + + +typedef enum stat +{ + RUNNING, + DONE, + CANCELLED +} eStat; + +typedef struct at_job +{ + int sec; + at_jobfunc_t *jobp; + void *arg; + eStat flag; +} at_job_t; + +static at_job_t *jobs[JOB_MAX]; +static int inited = 0; +static struct sigaction sa, alrm_sa_save; + +static int find_id( ) +{ + int i; + + for (i = 0; i < JOB_MAX; i++) + { + if (NULL == jobs[i]) + return i; + } + + return -ENOSPC; +} + +static void alrm_action(int sig, siginfo_t *infop, void *ucontext) +{ + int i; + + //* 判断信号来源 + if (SI_KERNEL != infop->si_code) + return; + + for (i = 0; i < JOB_MAX; i++) + { + if (jobs[i] != NULL) + { + jobs[i]->sec -= 1; + if (0 == jobs[i]->sec) + { + jobs[i]->jobp(jobs[i]->arg); + jobs[i]->flag = DONE; + } + } + } +} + +static void unload_module( ) +{ + int i; + struct itimerval itv; + + sigaction(SIGALRM, &alrm_sa_save, NULL); + if (errno != 0) + { + perror("sigaction"); + exit(1); + } + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL, &itv, NULL); + if (errno != 0) + { + perror("setitimer"); + exit(1); + } + + for (i = 0; i < JOB_MAX; i++) + { + if (NULL != jobs[i]) + free(jobs[i]); + } +} + +static void load_module( ) +{ + struct sigaction sa; + struct itimerval itv; + + sa.sa_sigaction = alrm_action; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; // 表示使用sigaction三参数的形式 + + sigaction(SIGALRM, &sa, &alrm_sa_save); + if (errno != 0) + { + perror("sigaction"); + exit(1); + } + + itv.it_interval.tv_sec = 1; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = 1; + itv.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL, &itv, NULL); + if (errno != 0) + { + perror("setitimer"); + exit(1); + } + + atexit(unload_module); //!!! atexit() +} + +int at_addjob(int sec, at_jobfunc_t *jobp, void *arg) +{ + if (sec < 0 || jobp == NULL) + return -EINVAL; + + if (!inited) + { + load_module( ); + inited = 1; + } + + at_job_t *job; + int id; + + job = malloc(sizeof(*job)); + if (NULL == job) + return -ENOMEM; + + job->sec = sec; + job->jobp = jobp; + job->arg = arg; + job->flag = RUNNING; + id = find_id( ); + if (id < 0) + return -ENOSPC; + + jobs[id] = job; + return id; +} + +int at_canceljob(int id) +{ + if (id < 0 || id >= JOB_MAX) + return -EINVAL; + + at_job_t *job = jobs[id]; + if (job == NULL) + return -EINVAL; + + if (job->flag == DONE) + return -EBUSY; + + if (job->flag == CANCELLED) + return -ECANCELED; + + jobs[id]->flag = CANCELLED; + + return 0; +} + +int at_waitjob(int id) +{ + if (id < 0 || id >= JOB_MAX) + return -EINVAL; + + at_job_t *job = jobs[id]; + if (job == NULL) + return -EINVAL; + + if (job->flag == RUNNING) + return -EINVAL; + + free(job); + jobs[id] = NULL; + + return 0; +} \ No newline at end of file diff --git a/C16-并发/parallel/signal/anytimer/anytimer.h b/C16-并发/parallel/signal/anytimer/anytimer.h index 81e8e3f..2a1aa5e 100644 --- a/C16-并发/parallel/signal/anytimer/anytimer.h +++ b/C16-并发/parallel/signal/anytimer/anytimer.h @@ -1,3 +1,14 @@ +/******************************************************************** + * @file anytimer.h + * @brief + * 单一计时器实现任意数量定时器 + * @author lzy (lllzzzyyy@buaa.edu.cn) + * @url https://lzyyyyyy.fun + * + * @date 2024-05-27 + * + ********************************************************************/ + #ifndef __ANYTIMER__H__ #define __ANYTIMER__H__ @@ -40,7 +51,6 @@ int at_canceljob(int id); ********************************************************************/ int at_waitjob(int id); - int at_pausejob(int id); int at_resumejob(int id); diff --git a/C16-并发/parallel/signal/anytimer/main.c b/C16-并发/parallel/signal/anytimer/main.c index 859f21b..8c48249 100644 --- a/C16-并发/parallel/signal/anytimer/main.c +++ b/C16-并发/parallel/signal/anytimer/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include static void f1(void *p) @@ -11,7 +12,7 @@ static void f1(void *p) static void f2(void *p) { - printf("f1():%s\n", (char *)p); + printf("f2():%s\n", (char *)p); } int main(int argc, char **argv) @@ -27,8 +28,23 @@ int main(int argc, char **argv) exit(1); } + job1 = at_addjob(2, f2, "bbb"); + if (job1 < 0) + { + fprintf(stderr, "at_addjob() failed!:%s\n", strerror(-job1)); + exit(1); + } + + job1 = at_addjob(7, f1, "ccc"); + if (job1 < 0) + { + fprintf(stderr, "at_addjob() failed!:%s\n", strerror(-job1)); + exit(1); + } + puts("End!"); + while (1) { write(1, ".", 1);