C语言实现任务调度与定时器

article/2025/9/5 0:39:11

代码实现是在xl2tpd的源码中get到的,感觉很有意思的一段代码。基本功能就是实现定时器,时间到后从定时队列中取出,然后完成指定的任务。

1. schedule.c代码(自己添加了main函数,用来调试)

/** Layer Two Tunnelling Protocol Daemon* Copyright (C) 1998 Adtran, Inc.* Copyright (C) 2002 Jeff McAdams** Mark Spencer** This software is distributed under the terms* of the GPL, which you should have received* along with this source.** Scheduler code for time based functionality**/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include "scheduler.h"struct schedule_entry *events;
static struct timeval zero;
static sigset_t alarm;/*init_scheduler配合schedule_lock,schedule_unlock使用,用来屏蔽当前进程中特定协议的处理
*/
void init_scheduler (void)/*初始化了两个不同的信号集*/
{struct sigaction act;act.sa_handler = alarm_handler;/*alarm信号执行体*/
#if defined (LINUX) && (__i386__)act.sa_restorer = NULL;
#endifact.sa_flags = 0;sigemptyset (&act.sa_mask);sigaddset (&act.sa_mask, SIGALRM);/*将SIGALRM信号添加到信号集sa_mask中,SIGALRM信号会阻塞*/sigaction (SIGALRM, &act, NULL);/*安装登记信号*/events = NULL;zero.tv_usec = 0;zero.tv_sec = 0;sigemptyset (&alarm);sigaddset (&alarm, SIGALRM);/*将SIGALRM信号添加到信号集alarm中,SIGALRM信号会阻塞*/
}void alarm_handler (int signal)
{/* Check queue for events which should beexecuted right now.  Execute them, thensee how long we should set the next timer*/struct schedule_entry *p = events;struct timeval now;struct timeval then;struct itimerval itv;static int cnt = 0;cnt++;if (cnt != 1){/* Whoa, we got called from within ourselves! *///log (LOG_DEBUG, "%s : Whoa... cnt = %d\n", __FUNCTION__, cnt);return;}while (events){gettimeofday (&now, NULL);p = events;if (TVLESSEQ (p->tv, now)){events = events->next;/* This needs to be executed, as it has expired.It is expected that p->func will free p->dataif it is necessary */(*p->func) (p->data);free (p);}elsebreak;}/* When we get here, either there are no more eventsin the queue, or the remaining events need to happenin the future, so we should schedule another alarm */if (events){then.tv_sec = events->tv.tv_sec - now.tv_sec;then.tv_usec = events->tv.tv_usec - now.tv_usec;if (then.tv_usec < 0){then.tv_sec -= 1;then.tv_usec += 1000000;}if ((then.tv_sec <= 0) && (then.tv_usec <= 0)){//log (LOG_WARN, "%s: Whoa...  Scheduling for <=0 time???\n",__FUNCTION__);}else{itv.it_interval = zero;itv.it_value = then;setitimer (ITIMER_REAL, &itv, NULL);/*重新定时,时间到后发送SIGALRM信号*/}}cnt--;
}void schedule_lock ()/*将alarm添加到当前进程阻塞信号集中,信号来时会被阻塞,暂时捕获不到,移除后会捕获?/
{while (sigprocmask (SIG_BLOCK, &alarm, NULL));
};void schedule_unlock ()/*将alarm从当前进程阻塞信号集中移除*/
{/* See if we missed any events */
/*	alarm_handler(0); */while (sigprocmask (SIG_UNBLOCK, &alarm, NULL));raise (SIGALRM);/*用来向本进程发送信号*/
};struct schedule_entry *schedule (struct timeval tv, void (*func) (void *),void *data)
{/* Schedule func to be run at relative time tv with dataas arguments.  If it has already expired, run it immediately.  The queue should be in order ofincreasing time */struct schedule_entry *p = events, *q = NULL;  /*时间间隔递增的队列*/int need_timer = 0;struct timeval diff;struct itimerval itv;							/*队列中越靠前,越早发生*/diff = tv;gettimeofday (&tv, NULL);tv.tv_sec += diff.tv_sec;  /*转换为本地系统时间*/tv.tv_usec += diff.tv_usec;if (tv.tv_usec > 1000000){tv.tv_sec++;tv.tv_usec -= 1000000;/*进制转换*/}while (p)				{if (TVLESS (tv, p->tv)) /*tv < p->tv*/break;q = p;p = p->next;};if (q){q->next =(struct schedule_entry *) malloc (sizeof (struct schedule_entry));q = q->next;}else{	/*时间比队列中的第一个时间还小*/q = (struct schedule_entry *) malloc (sizeof (struct schedule_entry));events = q;need_timer = -1;}q->tv = tv;q->func = func;q->data = data;q->next = p;if (need_timer){itv.it_interval = zero;itv.it_value = diff;setitimer (ITIMER_REAL, &itv, NULL); /*重新修改定时*/}return q;}inline struct schedule_entry *aschedule (struct timeval tv,/*tv传递的为绝对时间*/void (*func) (void *), void *data)
{/* Schedule func to be run at absolute time tv in the future with dataas arguments */struct timeval now;gettimeofday (&now, NULL);tv.tv_usec -= now.tv_usec;if (tv.tv_usec < 0){tv.tv_usec += 1000000;tv.tv_sec--;}tv.tv_sec -= now.tv_sec;return schedule (tv, func, data);
}void deschedule (struct schedule_entry *s)/*取消任务*/
{struct schedule_entry *p = events, *q = NULL;if (!s)return;while (p){if (p == s){if (q){q->next = p->next;}else{events = events->next;}free (p);break;}q = p;p = p->next;}
}
/*****************************************************************/
void func_test(void *data)
{struct timeval tv;	tv.tv_sec = 5;tv.tv_usec = 0;printf("落霞与孤鹜齐飞,秋水共长天一色\n");schedule(tv, func_test, NULL);
}void main(int argc, char *argv[])
{struct timeval tv;struct timeval timeout;printf("------scheduler-------\n");init_scheduler ();tv.tv_sec = 5;tv.tv_usec = 0;schedule(tv, func_test, NULL);timeout.tv_sec = 1;timeout.tv_usec = 0;while(1){select(0,NULL,NULL,NULL, &timeout);}
}

2. schedule.h

/** Layer Two Tunnelling Protocol Daemon* Copyright (C) 1998 Adtran, Inc.* Copyright (C) 2002 Jeff McAdams** Mark Spencer** This software is distributed under the terms* of the GPL, which you should have received* along with this source.** Scheduler structures and functions**/#ifndef _SCHEDULER_H
#define _SCHEDULER_H
#include <sys/time.h>/** The idea is to provide a general scheduler which can schedule* events to be run periodically*/struct schedule_entry
{struct timeval tv;          /* Scheduled time to execute */void (*func) (void *);      /* Function to execute */void *data;                 /* Data to be passed to func */struct schedule_entry *next;        /* Next entry in queue */
};extern struct schedule_entry *events;/* Schedule func to be executed with argument data sometimetv in the future. */struct schedule_entry *schedule (struct timeval tv, void (*func) (void *),void *data);/* Like schedule() but tv represents an absolute time in the future */struct schedule_entry *aschedule (struct timeval tv, void (*func) (void *),void *data);/* Remove a scheduled event from the queue */void deschedule (struct schedule_entry *);/* The alarm handler */void alarm_handler (int);/* Initialization function */
void init_scheduler (void);/* Prevent the scheduler from running */
void schedule_lock ();/* Restore normal scheduling functions */
void schedule_unlock ();/* Compare two timeval functions and see if a <= b */#define TVLESS(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec < (b).tv_usec) : \((a).tv_sec < (b).tv_sec))
#define TVLESSEQ(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec <= (b).tv_usec) : \((a).tv_sec <= (b).tv_sec))
#define TVGT(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec > (b).tv_usec) : \((a).tv_sec > (b).tv_sec))
#endif

3. 最简单的Makefile

​
CC = gcc
CFLAGS = -g
LFLAGS = 
OBJS = scheduler.o
all : scheduler
scheduler : $(OBJS)$(CC) $^ -o $@ $(LFLAGS)%*.o:%*.c$(CC) $(CFLAGS) $< -o $@.PHNOY: clean
clean:rm *.o scheduler

4. demo结果

调度时,每隔5秒钟,执行一次func_tesr()。
在这里插入图片描述
​​​​​


http://chatgpt.dhexx.cn/article/7ZiX2TSx.shtml

相关文章

c语言 精确定时程序,微调定时精确时间

1.定时器&蜂鸣器 一般定时器中断函数里的内容最好是能够快速地去执行完,比如只执行几条简单的语句,这样与主函数配合才会使程序更加高效。前期教学里,我们只使用定时器中断负责某个IO引脚间隔跳变或者使一个变量间隔自加1的简单语句。 比如我们现在要实现间隔50ms左右的…

c语言实现任务调度器

一、介绍 调度器是常用的一种编程框架&#xff0c;也是操作系统的拆分多任务的核心&#xff0c;比如单片机的裸机程序框架&#xff0c;网络协议栈的框架如can网关、485网关等等&#xff0c;使用场合比较多&#xff0c;是做稳定产品比较常用的编程技术 二、原理 1、超级循环 v…

C语言定时1分钟程序,C语言操作时间函数,实现定时执行某个任务小程序

时间操作函数在实际项目开发中会经常用到,最近做项目也正好用到就正好顺便整理一下。 时间概述 由上图可知:通过系统调用函数time()可以从内核获得一个类型为time_t的1个值,该值叫calendar时间,即从1970年1月1日的UTC时间从0时0分0妙算起到现在所经过的秒数。而该时间也用于…

vivado 2018.2官方下载

前几天想装vivado&#xff0c;奈何学长给的文件安装出了点问题&#xff0c;百度网盘下载20g又太慢&#xff0c;去官网看了一下&#xff0c;发现官网的安装器挺小的。 下载地址&#xff1a;https://china.xilinx.com/support/download.html 需要再注册一下就好。 之后的安装步骤…

vivado2021.1安装

首先需要在官网注册一个账号&#xff0c;安装软件时需要使用。 账号注册连接&#xff1a;xilink账号注册 vivado下载链接 xilink官网下载(使用官网下载需要注册账号&#xff0c;下载免费&#xff09; vivado阿里云盘下载 vivado licence阿里云盘下载 官网下载选择此项 下载完成…

Vivado 2020.1 开放下载,中文资料随贴奉送

Vivado 2020.1 开放下载了&#xff01;&#xff01; 以下都是重点&#xff01; 新 功能 Vivado 2020.1 新增以下功能&#xff1a; 能够将完整的图像或选定的产品作为 Web 安装程序的一部分增强的地址映射&#xff0c;用于实时错误高亮显示和交叉探测Report QoR Suggestions 功能…

vivado/vitis2020.2安装下载教程(适用于2019后版本)

1.解压安装包到当前文件夹。 2.右击以管理员身份运行。 3.提示下载最新的版本&#xff0c;不要下载&#xff0c;点击【Continue】&#xff0c;如果没弹出来这个就不管&#xff0c;然后点击【next】。 4.选择安装工具&#xff0c;选择安装完全体【vitis】&#xff0c;继续…

FPGA开发软件(vivado + modelsim)环境搭建(附详细安装步骤+软件下载)

本文详细介绍了vivado软件和modelsim软件的安装&#xff0c;以及vivado中配置modelsim仿真设置&#xff0c;每一步都加文字说明和图片。 一、软件安装包下载 1、vivado vivado版本很多&#xff0c;目前最新的已更新到vivado2022.2&#xff0c;版本越高&#xff0c;安装包越大&…

基于Vivado的程序下载

Vivado下bit文件下载步骤 将电源、下载器与板卡连接&#xff0c;打开Vivado工程&#xff0c;参考《基于TcL脚本生成Vivado工程及编译》文档编译工程&#xff0c;生成对应的bit文件。 打开板卡电源开关&#xff0c;找到右下角的”Open Hardware Manager”展开&#xff0c;右击…

Vivado® ML Editions 2022.2 最新更新(附下载链接)

本文由 AMD Vivado ML Editions 产品营销经理 Snehal Ullagaddi 撰写 AMD XILINX 近期全新推出了 Vivado ML Editions 2022.2 版给工具集带来了多项重大改进与增强功能。 主要亮点 推出电源设计管理器&#xff1a; 电源设计管理器 (PDM) 是全新的下一代功耗评估平台&#xff…

Vivado全版本下载分享

Vivado是由Xilinx公司开发的一款用于FPGA设计和开发的综合设计环境。它包括了高层次综合&#xff08;HLS&#xff09;、逻辑设计、约束管理、IP核管理、仿真、综合、实现和调试等功能&#xff0c;支持面向最新FPGA器件的设计。 这里分享一下Vivado的电脑安装配置推荐&#xff…

Vivado2019.2下载(官网百度云)与安装(手把手)

龙芯杯对于vivado版本的要求&#xff1a; Vivado Design Suite HL WebPACK™ 版是革命性设计套件的免费版本。我们用它&#xff0c;能满足龙芯杯的需要&#xff0c;而且不用license 区别如下&#xff1a; 下载地址 记得创建xilinx账号或者登陆&#xff01;&#xff01;&#…

Vivado2018.3的下载安装

文章目录 一、下载二、安装过程三、参考资料 一、下载 Vivado 官网下载地址&#xff1a;https://www.xilinx.com/support/download.html百度网盘地址&#xff1a;https://pan.baidu.com/s/1j1lkZJrTDNJB-2dCI0et_g &#xff08;提取码&#xff1a;s2lg &#xff09; 说明&…

XILINX VIVADO2018.2官方下载全教程记录.

毕设涉及FPGA&#xff0c;准备记录一下准备过程。 首先是Vivado的下载过程。 1.进入赛灵思下载官网。(https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html) 2.注册用户&#xff08;已有账号跳过&#xff09;…

官网下载 Vivado

1、使用 谷歌浏览器 点击如下链接进入下载界面 https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive.html 2、下一步&#xff0c;登陆你的XILINX账号&#xff0c;然后就可以下载了

Vivado官网下载

https://www.xilinx.com/support/download.html &#xff08;需要注册一个AMD账号&#xff0c;之后即可免费下载&#xff09; 下载成功后开始安装&#xff1a; 默认配置即可&#xff0c;50多G

VIVADO下载过程以及【卡在optimize disk usage】的解决办法

VIVADO下载过程以及【卡在optimize disk usage】的解决办法 一. 前言二.VIVADO下载步骤三 .可能遇到的问题 一. 前言 首先说明的是vivado下载并不难&#xff0c;只是因为它的软件包过于庞大&#xff0c;多达40多个G&#xff0c;耗时较长。因为官网对软件包的下载限制&#xff…

vivado及ISE各版本软件下载方法、链接及详细步骤,官方网页下载

本文介绍的下载方法为官方下载方法&#xff0c;使用浏览器下载&#xff0c;可使用迅雷加速下载 若需要网盘下载参照其他博主文章 官方下载需要注册AMD账号&#xff0c;使用QQ邮箱即可。 1、下载链接 Downloads (xilinx.com) 2、版本选择 左边选择需要下载的vivado软件版本…

vivado下载步骤

1.去xilinx官网 https://china.xilinx.com/support/download.html 2.点击对应版本链接往下翻&#xff0c;直到找到20G文件链接。 3.填写弹出的表格&#xff08;注意&#xff1a;最后一项&#xff0c;学生&#xff09;。 4.等待下载完成。

Vivado2018.3手把手详细下载

Vivado2018.3手把手详细下载 很多人在下载vivado的时候很头疼&#xff0c;牛马哥也是一样&#xff0c;下载了巨久。所有这里带大家手把手下载。 1、官网下载安装包 ​ 先找到vivado官网&#xff0c;注册xilinx的账号&#xff0c;在他们的产品里面找到vivado。因为我们要下载的…