Linux中的工作队列
工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化,因此本文分成两个部分对2.6.20之前和之后的版本分别做介绍。
I、2.6.0~2.6.19
|
1
2
3
4
5
6
7
8
|
struct work_struct { unsigned long pending; struct list_head entry; void (*func)(void *); void *data; void *wq_data; struct timer_list timer;}; |
pending是用来记录工作是否已经挂在队列上;
entry是循环链表结构;
func作为函数指针,由用户实现;
data用来存储用户的私人数据,此数据即是func的参数;
wq_data一般用来指向工作者线程(工作者线程参考下文);
timer是推后执行的定时器。
work_struct的这些变量里,func和data是用户使用的,其他是内部变量,我们可以不用太过关心。
API:
|
1
2
3
4
5
|
INIT_WORK(_work, _func, _data);int schedule_work(struct work_struct *work);int schedule_delayed_work(struct work_struct *work, unsigned long delay);void flush_scheduled_work(void);int cancel_delayed_work(struct work_struct *work); |
1、初始化指定工作,目的是把用户指定的函数_func及_func需要的参数_data赋给work_struct的func及data变量。
2、对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。
3、延迟执行工作,与schedule_work类似。
4、刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。
5、flush_scheduled_work并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work。
以上均是采用缺省工作者线程来实现工作队列,其优点是简单易用,缺点是如果缺省工作队列负载太重,执行效率会很低,这就需要我们创建自己的工作者线程和工作队列。
API:
|
1
2
3
4
5
|
struct workqueue_struct *create_workqueue(const char *name);int queue_work(struct workqueue_struct *wq, struct work_struct *work);int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay);void flush_workqueue(struct workqueue_struct *wq);void destroy_workqueue(struct workqueue_struct *wq); |
1、创建新的工作队列和相应的工作者线程,name用于该内核线程的命名。
2、类似于schedule_work,区别在于queue_work把给定工作提交给创建的工作队列wq而不是缺省队列。
3、延迟执行工作。
4、刷新指定工作队列。
5、释放创建的工作队列。
下面一段代码可以看作一个简单的实作:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void my_func(void *data){ char *name = (char *)data; printk(KERN_INFO “Hello world, my name is %s!\n”, name);}struct workqueue_struct *my_wq = create_workqueue(“my wq”);struct work_struct my_work;INIT_WORK(&my_work, my_func, “Jack”);queue_work(my_wq, &my_work);destroy_workqueue(my_wq); |
II、2.6.20~2.6.??
数据结构:
|
1
2
3
4
5
6
7
|
typedef void (*work_func_t)(struct work_struct *work);struct work_struct { atomic_long_t data; struct list_head entry; work_func_t func;}; |
与2.6.19之前的版本相比,work_struct瘦身不少。粗粗一看,entry和之前的版本相同,func和data发生了变化,另外并无其他的变量。
entry我们不去过问,这个和以前的版本完全相同。data的类型是atomic_long_t,这个类型从字面上看可以知道是一个原子类型。第一次看到这个变量时,很容易误认为和以前的data是同样的用法,只不过类型变了而已,其实不然,这里的data是之前版本的pending和wq_data的复合体,起到了以前的pending和wq_data的作用。
func的参数是一个work_struct指针,指向的数据就是定义func的work_struct。
看到这里,会有两个疑问,第一,如何把用户的数据作为参数传递给func呢?以前有void *data来作为参数,现在好像完全没有办法做到;第二,如何实现延迟工作?目前版本的work_struct并没有定义timer。
解决第一个问题,需要换一种思路。2.6.20版本之后使用工作队列需要把work_struct定义在用户的数据结构中,然后通过container_of来得到用户数据。具体用法可以参考稍后的实作。
对于第二个问题,新的工作队列把timer拿掉的用意是使得work_struct更加单纯。首先回忆一下之前版本,只有在需要延迟执行工作时才会用到timer,普通情况下timer是没有意义的,所以之前的做法在一定程度上有些浪费资源。所以新版本中,将timer从work_struct中拿掉,然后又定义了一个新的结构delayed_work用于处理延迟执行:
|
1
2
3
4
|
struct delayed_work { struct work_struct work; struct timer_list timer;}; |
下面把API罗列一下,每个函数的解释可参考之前版本的介绍或者之后的实作:
|
1
2
3
4
5
6
7
8
9
10
11
|
INIT_WORK(struct work_struct *work, work_func_t func);INIT_DELAYED_WORK(struct delayed_work *work, work_func_t func);int schedule_work(struct work_struct *work);int schedule_delayed_work(struct delayed_work *work, unsigned long delay);struct workqueue_struct *create_workqueue(const char *name);int queue_work(struct workqueue_struct *wq, struct work_struct *work);int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay);void flush_scheduled_work(void);void flush_workqueue(struct workqueue_struct *wq);int cancel_delayed_work(struct delayed_work *work);void destroy_workqueue(struct workqueue_struct *wq); |
其中,1、2、4、7和以前略有区别,其他用法完全一样。
实作:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
struct my_struct_t { char *name; struct work_struct my_work;};void my_func(struct work_struct *work){ struct my_struct_t *my_name = container_of(work, struct my_struct_t, my_work); printk(KERN_INFO “Hello world, my name is %s!\n”, my_name->name);}struct workqueue_struct *my_wq = create_workqueue(“my wq”);struct my_struct_t my_name;my_name.name = “Jack”;INIT_WORK(&(my_name.my_work), my_func);queue_work(my_wq, &(my_name.my_work));destroy_workqueue(my_wq); |
作者:wwang
出处:http://www.cnblogs.com/wwang
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
--------懒人评论(请勿重复点击)--------
Linux中的工作队列的更多相关文章
- 【转】 Linux中的工作队列
原文网址:http://blog.chinaunix.net/uid-20583479-id-1920134.html 工作队列一般用来做滞后的工作,比如在中断里面要做很多事,但是比较耗时,这时就可以 ...
- 聊一聊Linux中的工作队列2
上一篇文章对工作队列原理以及核心数据结构做了简单介绍,本文重点介绍下workqueue的创建以及worker的管理. 一.工作队列的创建(__alloc_workqueue_key) struct w ...
- 聊一聊Linux中的工作队列
2018-01-18 工作队列是Linux内核中把工作延迟执行的一种手段,其目的不同于软中断,软中断是提高CPU的响应,尽可能的缩短关中断的时间:而工作队列主要目的是节省资源,其比较适合很微小的任务, ...
- 浅析Linux中的进程调度
2016-11-22 前面在看软中断的时候,牵扯到不少进程调度的知识,这方面自己确实一直不怎么了解,就趁这个机会好好学习下. 现代的操作系统都是多任务的操作系统,尽管随着科技的发展,硬件的处理器核心越 ...
- linux中的tasklet机制【转】
转自:http://blog.csdn.net/yasin_lee/article/details/12999099 转自: http://www.kerneltravel.net/?p=143 中断 ...
- Linux中断分层--工作队列
1. 工作队列是一种将任务推后执行的方式,它把推后的任务交由一个内核线程去执行.这样中断的下半部会在进程上下文执行,他允许重新调度甚至睡眠.每个被推后的任务叫做“工作”,由这些工作组成的队列称为工作队 ...
- 在 Linux 中安装 Oracle JDK 8 以及 JVM 的类加载机制
参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...
- Linux中find常见用法示例
·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数: pathname: find命 ...
- Linux中检索文件
1 , Use locate command It is a fast way to find the files location, but if a file just created ,it w ...
随机推荐
- hdu4405:Aeroplane chess
题目大意:有编号为0-n的格子,从0开始,扔骰子扔到几就走几格.有m个瞬移点,每个点可以从格x直接飞到格y,若瞬移到另一个瞬移点可以继续瞬移.求到达格n的期望扔骰子次数. 题解:期望DP入门好题.网上 ...
- msp430项目编程23
msp430中项目---风扇控制系统 1.比较器工作原理 2.电路原理说明 3.代码(显示部分) 4.代码(功能实现) 5.项目总结 msp430项目编程 msp430入门学习
- Java面试题总结(一)---Java基础
Java面试题总结(一)---Java基础 1.面向对象的特征有哪些? 答:面向对象的特征主要有以下几个: 1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方 ...
- Date日期模式
package cn.zmh.Date; import java.text.SimpleDateFormat; import java.util.Date; public class DateDemo ...
- http 连接失败重连机制
1.我们做web开发时,需要经常使用httpclient来请求http服务,有时为了安全起见,服务提供方会提供多个http地址,这样如果我们请求某个ip出现异常,可以重试其他的ip地址,来尽量保证系统 ...
- HDU 4115 Eliminate the Conflict(2-sat)
HDU 4115 Eliminate the Conflict pid=4115">题目链接 题意:Alice和Bob这对狗男女在玩剪刀石头布.已知Bob每轮要出什么,然后Bob给Al ...
- Duplicate property mapping of contactPhone found in
启动的时候报Duplicate property mapping of contactPhone found in com....的错误,是因为在建立实体对象的时候,有字段重复了,有的是继承了父类的字 ...
- Codeforces div.2 B. The Child and Set
题目例如以下: B. The Child and Set time limit per test 1 second memory limit per test 256 megabytes input ...
- kill mediaserver脚本
#!/bin/bash adb shell kill $(adb shell ps | grep mediaserver | awk '{print $2}') adb shell pm clear ...
- 2016/4/5 Ajax ①用户名 密码 登陆 注册 ② 判断用户名是否已存在 ③点击按钮出现民族选项下拉菜单 ④DBDA类 加入Ajaxquery方法 数组变字符串 字符串拆分
①登陆 注册 查表匹配 0405Ajax.php ②判断用户名是否存在 <!DOCTYPE html> <html lang="en"> ...