延迟:
一,内核定时器
1,内核定时器用在延迟指定时长之后调度异步函数执行(调度异步函数在延迟指定时长之后执行);
2,内核定时器在 “软件中断”上下文中,以院子模式运行,所以就会有众多限制:
1》不能访问用户空间,由于在软件中断上下文中,所以没有与用户空间进程相关的进程资源,所以无法访问用户空间;
2》在原子模式下current指针失效,
3》定时器异步函数中不能休眠与调度,由于在软件中断上下文中运行,所以禁止休眠,也不能使用信号量,因为信号量可能引起休眠,只能使用自旋锁(spinlock_t),原子变量(atomic_t) 机制
需要注意的问题:由于定时器函数异步执行,必然会带来资源的竞态访问问题,所以定时器函数访问的数据结构必须针对并发访问进行控制;
措施:使用自旋锁(spinlock_t),原子变量(atomic_t);
3,linux内核定时器的实现:
头文件:<linux/timer.h>
数据结构:struct timer_list{... , unsigned long expires,void(*function)(unsigned long),unsigned long data};
操作: 初始化:DEFINE_TIMER(timer,expires,function,data);//编译时静态初始化;
void init_timer(struct timer_list *);//运行时动态初始化;
添加:void add_timer(struct timer_list *);
移除:void del_timer(struct timer_list *);
二,tasklet
tasklet 和内核定时器运行原理一样,都是在"软件中断"上下文中以原子模式运行,所以限制条件也一样,但是没有定时器的时间限制,所以就没有定时器对时间的要求精确;
数据结构:struct tasklet_struct {... , void (*func)(unsigned long),unsigned long};
操作:初始化:DECLARE_TASKLET(tasklet,func,data);//静态初始化;
DECLARE_TASKLET_DISABLED(tasklet,func,data);//静态初始化为不能被调度的tasklet;
tasklet_init(struct tasklet_struct *,void (*func)(unsigned long),unsigned long);//运行时动态初始化;
调度执行:schedule_tasklet(struct tasklet_struct *);
schedule_hi_tasklet(struct tasklet_struct *);//高优先级调度;
设置不可调度:tasklet_disable(struct tasklet_struct *);
启用tasklet:tasklet_enable(struct tasklet_struct *);
撤销:tasklet:tasklet_kill(struct tasklet_struct *);
三,workqueue:
1,workqueue运行在特殊的内核进程中,所以workqueue不必以原子模式运行;
和tasklet的主要区别有两点:
1,tasklet运行在“软件中断”上下文中,必须快速在短时间内执行完毕,不能休眠和调度,必须以原子模式运行;
2,workqueue运行在特殊的内核进程中,所以可以延时一定时长再执行,可以休眠,不必以原子模式运行;
两者都不能访问用户空间;
2,数据结构:
struct workqueue {};
struct work_struct{...,void (*func)(unsigned long),unsigned long};
操作:创建队列:struct workqueue create_workqueue(void);