工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。

工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化,因此本文分成两个部分对2.6.20之前和之后的版本分别做介绍。

I、2.6.0~2.6.19

数据结构:

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:

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:

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、释放创建的工作队列。

下面一段代码可以看作一个简单的实作:

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.??

自2.6.20起,工作队列的数据结构发生了一些变化,使用时不能沿用旧的方法。

数据结构:

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用于处理延迟执行:

struct delayed_work {
struct work_struct work;
struct timer_list timer;
};

下面把API罗列一下,每个函数的解释可参考之前版本的介绍或者之后的实作:

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和以前略有区别,其他用法完全一样。

实作:

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);

Linux中的工作队列相关推荐

  1. linux中的tasklet机制【转】

    转自:http://blog.csdn.net/yasin_lee/article/details/12999099 转自: http://www.kerneltravel.net/?p=143 中断 ...

  2. Linux中的中断管理机制

    1.中断相关基础知识介绍 1.1.中断产生背景 假设现在CPU需要去获取一个键盘的时间,如果处理器发出一个请求信号之后一直在轮询键盘的响应,由于键盘响应速度比处理器慢得多并且需要等待用户输入,这对于C ...

  3. imx6 通过移植XRM117x(SPI转串口)对Linux中的SPI驱动框架进行分析

    最近分析了一下Linux 中的SPI驱动框架,将自己的理解总结一下,不足之处还请斧正! 1.SPI通信基础知识 SPI(Serial Peripheral Interface)是一种串行(一次发送1b ...

  4. 分清概念十分重要之--Linux中的各种队列

    先列个框架,后续丰富完善. 提这个问题,是因为在Linux内核学习中,遇到过一个让人啼笑皆非的问题.这个问题是啥呢?提个引子,在实际生活中,可能每个人都有过这样的经历,就是总是将某两个明明完全不同的概 ...

  5. linux 中的中断处理

    谈谈对中断的理解 1.裸板中断处理过程 中断属于异常的一种 它是计算机中处理异步事件的重要机制1.1 中断的触发中断源级配置中断的触发方式 上升沿 下降沿 高 低触发中断使能 (监测到中断信号之后,能 ...

  6. Linux中的休眠函数

    一.简介 Linux中应用层和驱动层编写代码时都会用到延时,本文主要介绍两种情况下延时功能的实现. 1.应用层:sleep.usleep: 2.驱动层:udelay.mdelay.ssleep.通过j ...

  7. c++ 进程快照_如何在 Linux 中找出内存消耗最大的进程

    很多次,你可能遇见过系统消耗了过多的内存.如果是这种情况,那么最好的办法是识别出 Linux 机器上消耗过多内存的进程. -- Magesh Maruthamuthu(作者) 很多次,你可能遇见过系统 ...

  8. linux的tar中ztvf,linux中的tar命令(2)

    实例4:只将 /tar 内的 部分文件解压出来 命令: tar -zxvf /opt/soft/test/log30.tar.gz log2013.log 输出: [root@localhost te ...

  9. centos6.5 php5.2,Linux中PHP安装与配置(CentOS-6.5:php-5.2.13)

    1 PHP简介     PHP(PHP: Hypertext Preprocessor的缩写,中文名:"超文本预处理器")是一种通用开源脚本语言.语法吸收了C语言.Java和Per ...

最新文章

  1. 一秒看遍10万神经元的「绚丽烟花」,AI究竟向大脑学什么?|北大陈良怡专访...
  2. js转换html为pdf文件怎么打开方式,pdf.js实现在HTML下直接浏览pdf文档,无需插件即可实现...
  3. jquery中$.post()方法的简单实例
  4. Junit测试报错:java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
  5. yum安装php5.6 nginx,CentOS 7 yum安装 Nginx1.16 + MySQL5.5 PHP5.6
  6. html5的文档申明为什么是!DOCTYPE html?
  7. protobuf在java应用中通过反射动态创建对象
  8. PCB,原理图 最流行的画图画板软件有哪些?
  9. 数学建模优化模型简单例题_数学建模例题.doc
  10. [1140]linux查看历史命令history
  11. 简单描述数字签名:私钥签名;公钥验签。
  12. 24V转12V10A带使能脚同步整流AH2305D
  13. 今天测试twm000 850的windows7 记录
  14. 计算机无法打开pdf文件格式,pdf格式的文件打不开 [电脑打不开pdf格式文件怎么回事]...
  15. 二维数组和二维数组名
  16. Unity用代码批量修复材质球shader丢失的问题
  17. Tita绩效宝:通过组织透明度提高绩效
  18. 计算器并没有取代数学家,AI也不会取代人类
  19. Java集合篇:Map接口、Map接口的实现类、Collections集合工具类
  20. 管理是科学还是艺术呢?-----行动力

热门文章

  1. Installation failed, deleting ./composer.json.安装phpunit报错解决方案
  2. 重写laravel的request的校验器
  3. Flask 上下文源码解析
  4. 大数据之Kafka入门简介
  5. 机器学习之必知开源数据集
  6. 列的数目比列的名字要多_你们要的甘特图来啦!还有具体做法哦!
  7. C++ 虚函数经典深入解析
  8. oracle中pga指什么,oracle学习SGA跟PGA理解
  9. php 加密保存mysql_PHP及MYSQL中字符串加密函数
  10. 第七季1:MP4文件格式解析