C语言实现任务调度与定时器
代码实现是在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语言实现任务调度与定时器的更多相关文章
- Spring Task 任务调度(定时器)
		1.任务调度SpringTask 1.1什么是任务调度 在企业级应用中,经常会制定一些“计划任务”,即在某个时间点做某件事情,核心是以时间为关注点,即在一个特定的时间点,系统执行指定的一个操作.常见的 ... 
- C语言实现的多线程定时器
		目录 1. 大致功能介绍 2. API库介绍 3. 一个例子 4. 库文件源码 注意事项 1. 大致功能介绍 实现任务列表,定时器会间隔一段时间遍历列表发现要执行的任务 任务列表中的所有任务并行执行 ... 
- go语言之进阶篇定时器重置
		1.定时器重置 示例: package main import ( "fmt" "time" ) func main() { timer := time.New ... 
- go语言之进阶篇定时器停止
		1.定时器停止 示例: package main import ( "fmt" "time" ) func main() { timer := time.New ... 
- go语言之进阶篇定时器Timer的使用
		1.Timer的使用 示例: #创建一个定时器,设置时间为2s,2s后,往time通道写内容(当前时间) package main import ( "fmt" "tim ... 
- ESP8266 LUA脚本语言开发: 外设篇-定时器,延时,看门狗
		https://nodemcu.readthedocs.io/en/master/modules/tmr/ local mytimer1 = tmr.create() function TimeFun ... 
- 分布式任务调度平台XXL-JOB
		<分布式任务调度平台XXL-JOB> 一.简介 1.1 概述 XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速.学习简单.轻量级.易扩展.现已开放源代码并 ... 
- 原生js简单调用百度翻译API实现的翻译工具
		先来个在线demo: js翻译工具 或者百度搜索js简单调用百度翻译API工具(不过有个小小的界面显示bug,我想细心的人应该会发现) 或者直接前往该网址:js翻译工具 或者前往我的github:gi ... 
- JavaWeb学习笔记八 监听器
		监听器Listener jservlet规范包括三个技术点:servlet :listener :filter:监听器就是监听某个对象的的状态变化的组件.监听器的相关概念事件源: 被监听的对象(三个域 ... 
随机推荐
- js控制单选按钮选中某一项
			<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>& ... 
- Redis 实战篇:巧用数据类型实现亿级数据统计
			在移动应用的业务场景中,我们需要保存这样的信息:一个 key 关联了一个数据集合,同时还要对集合中的数据进行统计排序. 常见的场景如下: 给一个 userId ,判断用户登陆状态: 两亿用户最近 7 ... 
- 蓝凌OA前台任意文件读取漏洞利用
			近期CNVD爆出漏洞编号:CNVD-2021-28277,首次公开日期为2021-04-15,蓝凌oa存在多个漏洞,攻击者可利用该漏洞获取服务器控制权.今天挑选一个蓝凌OA前台任意文件读取漏洞进行分析 ... 
- Vue-Router学习第二弹动态路由\懒加载\嵌套路由
			在我们做项目时肯定会有出现动态路由: 举个栗子: 一个品种的商品页面会有同类不同样的商品就要在路由的后面加一个id: Vue的路由id是这样添加的: 两种动态路由 一种是params参数添加: 首先现 ... 
- 工资8000以下的Android程序员注意了!接下来要准备面对残酷现实了……
			最近在知乎看到一个测试,特扎心: 以下三种情况,哪个最让你绝望? ❶ 每月工资去掉开销还存不到3千: ❷ 家人突然急病住院,医药费10万: ❸ 同班的家长都在争先恐后给孩子报名各种辅导班.兴趣班,但一 ... 
- Google Breakpad · 基础介绍
			Google breakpad是一个跨平台的崩溃转储和分析框架和工具集合. 三个主要组件 ◆ client 以library的形式内置在你的应用中,当崩溃发生时写 minidump文件 ◆ symbo ... 
- 0基础学小程序----day2
			目录结构的三部分如上 下来我们看看 框架全局文件 app.js小程序逻辑 再看app.json 小程序公共设置可以对五个功能进行设置 我们再来逐一看看 页面路径那里 你建个路径,他会自动生成文件夹 ... 
- Innodb中怎么查看锁信息
			一.前言 上一篇说了下innodb中锁的大概意思, 这篇说说怎么查看加的哪些锁.不然后续出现死锁或者锁等待都不知道为什么. 二.底层基础表信息 在学会如何查看有哪些锁信息时, 需要了解一些基础表信息, ... 
- CMD直接输入Java,Javac,Javap发生乱码解决方式
			首先需要设置jdk的默认编码,在之前一篇博文里有 然后在cmd里直接执行chcp 65001 代表将cmd换成UTF-8的显示页 936是GBK 437为英语 
- docker部署Redis6-0-6
			下载redis.conf配置 下载地址: http://download.redis.io/redis-stable/redis.conf 拉取docker镜像 docker pull redis:6 ... 
