代码实现是在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;
#endif
act.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 be
executed right now. Execute them, then
see 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->data
if it is necessary */
(*p->func) (p->data);
free (p);
}
else
break;
}
/* When we get here, either there are no more events
in the queue, or the remaining events need to happen
in 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 data
as arguments. If it has already expired, run it
immediately. The queue should be in order of
increasing 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 data
as 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 sometime
tv 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()。

​​​​​

C语言实现任务调度与定时器的更多相关文章

  1. Spring Task 任务调度(定时器)

    1.任务调度SpringTask 1.1什么是任务调度 在企业级应用中,经常会制定一些“计划任务”,即在某个时间点做某件事情,核心是以时间为关注点,即在一个特定的时间点,系统执行指定的一个操作.常见的 ...

  2. C语言实现的多线程定时器

    目录 1. 大致功能介绍 2. API库介绍 3. 一个例子 4. 库文件源码 注意事项 1. 大致功能介绍 实现任务列表,定时器会间隔一段时间遍历列表发现要执行的任务 任务列表中的所有任务并行执行 ...

  3. go语言之进阶篇定时器重置

    1.定时器重置 示例: package main import ( "fmt" "time" ) func main() { timer := time.New ...

  4. go语言之进阶篇定时器停止

    1.定时器停止 示例: package main import ( "fmt" "time" ) func main() { timer := time.New ...

  5. go语言之进阶篇定时器Timer的使用

    1.Timer的使用 示例: #创建一个定时器,设置时间为2s,2s后,往time通道写内容(当前时间) package main import ( "fmt" "tim ...

  6. ESP8266 LUA脚本语言开发: 外设篇-定时器,延时,看门狗

    https://nodemcu.readthedocs.io/en/master/modules/tmr/ local mytimer1 = tmr.create() function TimeFun ...

  7. 分布式任务调度平台XXL-JOB

    <分布式任务调度平台XXL-JOB>       一.简介 1.1 概述 XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速.学习简单.轻量级.易扩展.现已开放源代码并 ...

  8. 原生js简单调用百度翻译API实现的翻译工具

    先来个在线demo: js翻译工具 或者百度搜索js简单调用百度翻译API工具(不过有个小小的界面显示bug,我想细心的人应该会发现) 或者直接前往该网址:js翻译工具 或者前往我的github:gi ...

  9. JavaWeb学习笔记八 监听器

    监听器Listener jservlet规范包括三个技术点:servlet :listener :filter:监听器就是监听某个对象的的状态变化的组件.监听器的相关概念事件源: 被监听的对象(三个域 ...

随机推荐

  1. (原创)[.Net] 进程间通信框架(基于共享内存)——SimpleMMF

    一.前言 进程间通信技术的应用非常广泛,在Windows下常用的实现方式有:管道.Socket.消息.本地文件.共享内存等,每种方式都有各自适应的场景. 在进行大数据交换时,最优的方式便是共享内存. ...

  2. [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现

    [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现 目录 [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现 0x00 摘要 0x01 基础类 1. ...

  3. flink clickhouse-jdbc和flink-connector 写入数据到clickhouse因为jar包冲突导致的60 seconds.Please check if the requested resources are available in the YARN cluster和Could not resolve ResourceManager address akka报错血案

    一.问题现象,使用flink on yarn 模式,写入数据到clickhouse,但是在yarn 集群充足的情况下一直报:Deployment took more than 60 seconds. ...

  4. elsa-core—2.Hello World: HTTP

    在本快速入门中,我们将了解一个执行工作流的最小 ASP.NET Core 应用程序.工作流将侦听传入的 HTTP 请求并写回一个简单的响应. 我们将: 创建 ASP.NET Core 应用程序. 使用 ...

  5. WPF listbox 实现动态滚轮下拉定位

    private ObservableCollection<keymodel> _listlua; public ObservableCollection<keymodel> l ...

  6. Git出错:“Please make sure you have the correct access rights and the repository exists.”

    此问题是需要重置ssh密钥 解决步骤如下: 1.重置用户名和邮箱: 打开Git Bash 进入Git命令,输入以下命令 git config --global user.name "你的用户 ...

  7. HTML重点总结

    HTML基础 1. 标题 HTML 标题(Heading)是通过<h1> - <h6> 标签来定义的. <h1>这是一个标题</h1> <h2&g ...

  8. HashMap底层实现-基础

    1.数据结构 1.7 数组+链表,键值对是以Entry内部类的数组存放的.键计算得到哈希值是该数组的下标.又称桶数组当存在哈希冲突时,会通过Entry类内部的成员变量 Entry<k,v> ...

  9. miniFTP项目实战三

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  10. noip30

    T1 一眼看,觉得是个状压,然而又觉得不太行,去打暴力了,然而暴力都打挂的我biss. 正解: 还是暴力,考虑 \(meet \; in \; the \; middle\) 显然对于每个数,只有三种 ...