您的位置:首页 > 运维架构 > Linux

Linux中Workqueue机制分析

2015-12-17 15:51 501 查看
什么是 workqueue ?

Linux 中的Workqueue 机制就是为了简化kernel线程的建立。通过呼叫workqueue 的介面就能建立kernel线程。并且可以根据当前系统CPU的个数建立线程的数量,使得线程处理的事务能够并行化。

workqueue 是kernel中实现简单而有效的机制,他显然简化了kerneldaemon 的建立,方便了用户的编程,

Workqueue 机制的实现

Workqueue 机制中定义了两个重要的数据结构,分析如下:

1、 cpu_workqueue_struct 结构。该结构将CPU和kernel线程进行了绑定。在建立workqueue 的过程中, Linux 根据当前系统CPU的个数建立cpu_workqueue_struct 。在该结构主要维护了一个任务队列,以及kernel线程需要睡眠的等待队列,另外还维护了一个任务上下文,即task_struct 。

2、 work_struct 结构是对任务的抽象。在该结构中需要维护具体的任务方法,需要处理的数据,以及任务处理的时间。该结构定义如下:

struct work_struct {
unsigned long pending;
struct list_head entry;/* 将任务挂载到queue 的挂载点*/
void (*func)(void *); /* 任务方法 */
void *data; /* 任务处理的数据*/
void *wq_data; /* work 的属主 */
strut timer_list timer;/* 任务延时处理定时器*/
};


当用户呼叫workqueue 的初始化介面create_workqueue 或者create_singlethread_workqueue 对workqueue 队列进行初始化时,kernel就开始为用户分配一个workqueue 对象,并且将其链到一个全局的workqueue 队列中。然后Linux 根据当前CPU的情况,为workqueue 对象分配与CPU个数相同的cpu_workqueue_struct 对象,每个cpu_workqueue_struct 对像都会存在一条任务队列。紧接着, Linux 为每个cpu_workqueue_struct 对象分配一个kernelthread ,即kerneldaemon 去处理每个队列中的任务。至此,用户呼叫初始化介面将workqueue 初始化完毕,返回workqueue 的指标。

在初始化workqueue 过程中,kernel需要初始化kernel线程,注册的kernel线程工作比较简单,就是不断的扫描对应cpu_workqueue_struct 中的任务队列,从中获取一个有效任务,然后执行该任务。所以如果任务队列为空,那么kerneldaemon 就在cpu_workqueue_struct 中的等待队列上睡眠,直到有人唤醒daemon 去处理任务队列。

Workqueue 初始化完毕之后,将任务运行的上下文环境构建起来了,但是具体还没有可执行的任务,所以,需要定义具体的work_struct 对象。然后将work_struct 加入到任务队列中, Linux 会唤醒daemon 去处理任务。

上述描述的workqueue kernel实现原理可以描述如下:



在Workqueue 机制中,提供了一个系统默认的workqueue 队列—— keventd_wq ,这个队列是Linux 系统在初始化的时候就建立的。用户可以直接初始化一个work_struct 对象,然后在该队列中进行调度,使用更加方便。

Workqueue 编程介面

1
create_workqueue
用于建立一个workqueue 队列,为系统中的每个CPU都建立一个kernel线程。

输入参数:
@name : workqueue 的名称

2
create_singlethread_workqueue 用于建立workqueue ,只建立一个kernel线程。

输入参数:
@name : workqueue 名称

3
destroy_workqueue
释放 workqueue 队列。

输入参数:
@ workqueue_struct :需要释放的workqueue 队列指标

4
schedule_work
调度执行一个具体的任务,执行的任务将会被挂入Linux 系统提供的workqueue —— keventd_wq

输入参数:
@ work_struct :具体任务对象指标

5
schedule_delayed_work
延迟一定时间去执行一个具体的任务,功能与schedule_work 类似,多了一个延迟时间,

输入参数:
@work_struct :具体任务对象指标
@delay :延迟时间

6
queue_work
调度执行一个指定workqueue 中的任务。

输入参数:
@ workqueue_struct :指定的 workqueue 指标
@work_struct :具体任务对象指标

7
queue_delayed_work
延迟调度执行一个指定workqueue 中的任务,功能与queue_work 类似,输入参数多了一个delay 。

基本顺序

1.创建工作队列
struct workqueue_struct *create_workqueue(const char *name);
struct workqueue_struct *create_singlethread_workqueue(const char *name);
2.创建工作
DECLARE_WORK(name, void (*function)(void *), void *data);
//一个函数搞定定义和初始化
INIT_WORK(struct work_struct *work, void (*function)(void *), void *data);
PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data);
//要先定义work_struct,再调用这两个函数
//INIT_WORK做更全的初始化,若需要改变工作队列,则用PREPARE_WORK

3.提交工作给一个工作队列
int queue_work(struct workqueue_struct *queue, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay);
//返回0,添加成功,非0表明已存在此工作
int cancel_delayed_work(struct work_struct *work);
//返回非0,取消成功,返回0,取消不成功,工作仍在运行
void flush_workqueue(struct workqueue_struct *queue);
//确保cancel_delayed_work调用返回0后,停止运行工作

4.删除队列
void destroy_workqueue(struct workqueue_struct *queue);
//用完后删掉工作队列
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: