工作队列是, 表面上看, 类似于 taskets; 它们允许内核代码来请求在将来某个时间调用 一个函数. 但是, 有几个显著的不同在这 2 个之间, 包括:

  • tasklet 在软件中断上下文中运行的结果是所有的 tasklet 代码必须是原子的. 相反, 工作队列函数在一个特殊内核进程上下文运行; 结果, 它们有更多的灵活性. 特别地, 工作队列函数能够睡眠.
  • tasklet 常常在它们最初被提交的处理器上运行. 工作队列以相同地方式工作, 缺 省地.
  • 内核代码可以请求工作队列函数被延后一个明确的时间间隔.

两者之间关键的不同是 tasklet 执行的很快, 短时期, 并且在原子态, 而工作队列函数 可能有高周期但是不需要是原子的.
每个机制有它适合的情形.

工作队列有一个 struct workqueue_struct 类型, 在
<linux/workqueue.h> 中定义. 一 个工作队列必须明确的在使用前创建, 使用一个下列的 2 个函数:

struct workqueue_struct *create_workqueue(const char
*name);

struct workqueue_struct
*create_singlethread_workqueue(const char *name);

每个工作队列有一个或多个专用的进程("内核线程"),
它运行提交给这个队列的函数. 如 果你使用 create_workqueue, 你得到一个工作队列它有一个专用的线程在系统的每个处 理器上. 在很多情况下, 所有这些线程是简单的过度行为;
如果一个单个工作者线程就足 够, 使用 create_singlethread_workqueue 来代替创建工作队列

提交一个任务给一个工作队列, 你需要填充一个 work_struct 结构. 这可以在编译时完 成, 如下:

DECLARE_WORK(name,
void (*function)(void *), void *data);

这里
name 是声明的结构名称, function 是从工作队列被调用的函数, 以及 data 是一 个传递给这个函数的值. 如果你需要建立
work_struct 结构在运行时, 使用下面 2 个宏 定义:

INIT_WORK(struct work_struct *work, void
(*function)(void *), void *data); PREPARE_WORK(struct work_struct *work, void
(*function)(void *), void *data);

INIT_WORK
做更加全面的初始化结构的工作; 你应当在第一次建立结构时使用它. PREPARE_WORK 做几乎同样的工作, 但是它不初始化用来连接 work_struct
结构到工作队 列的指针. 如果有任何的可能性这个结构当前被提交给一个工作队列, 并且你需要改变这 个队列, 使用 PREPARE_WORK 而不是
INIT_WORK.

有 2 个函数来提交工作给一个工作队列:

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

每个都添加工作到给定的队列.
如果使用 queue_delay_work, 但是, 实际的工作没有进 行直到至少 delay jiffies 已过去. 从这些函数的返回值是 0 如果工作被成功加入到队
列; 一个非零结果意味着这个 work_struct 结构已经在队列中等待, 并且第 2 次没有加 入.

在将来的某个时间, 这个工作函数将被使用给定的 data 值来调用. 这个函数将在工作者 线程的上下文运行,
因此它可以睡眠如果需要 -- 尽管你应当知道这个睡眠可能怎样影响

提交给同一个工作队列的其他任务. 这个函数不能做的是,
但是, 是存取用户空间. 因为 它在一个内核线程中运行, 完全没有用户空间来存取.

如果你需要取消一个挂起的工作队列入口, 你可以调用: int cancel_delayed_work(struct
work_struct *work);

返回值是非零如果这个入口在它开始执行前被取消.
内核保证给定入口的执行不会在调用 cancel_delay_work 后被初始化. 如果 cancel_delay_work 返回 0, 但是, 这个入口可 能已经运行在一个不同的处理器,
并且可能仍然在调用 cancel_delayed_work 后在运行. 要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行,
你必须跟 随这个调用来调用:

void
flush_workqueue(struct workqueue_struct *queue);

在 flush_workqueue 返回后, 没有在这个调用前提交的函数在系统中任何地方运行. 当你用完一个工作队列, 你可以去掉它, 使用:

void
destroy_workqueue(struct workqueue_struct *queue);

linux tasklet工作队列的更多相关文章

  1. 《深入理解Linux内核》软中断/tasklet/工作队列

    软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来.下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任 ...

  2. (linux)tasklet

      tasklet Tasklet的使用比较简单,只需要定义tasklet及其处理函数并将两者关联 例子: Void my_tasklet_func(unsigned long) DECLARE_TA ...

  3. Linux tasklet 和workqueue学习

    中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化.但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失.因 ...

  4. linux内核工作队列使用总结

    我总结出的内核工作队列中的4种用法 1. 使用系统的工作队列(不延迟) 1)定义一个工作: struct work_struct my_work; 2)编写一个函数: void my_work_fun ...

  5. Linux 内核工作队列之work_struct 学习总结

    前言 编写Linux驱动的时候对于work_struct的使用还是很普遍的,很早之前就在阅读驱动源码的时候就看到了它的踪影,根据其命名大概知道了它的具体作用,但是仍然不知所以,同时,伴随出现的还有de ...

  6. linux 驱动 工作队列

    http://blog.sina.com.cn/s/blog_78d30f6b0102uyaf.html http://blog.csdn.net/lyc_stronger/article/detai ...

  7. linux Tasklet 实现

    记住 tasklet 是一个特殊的函数, 可能被调度来运行, 在软中断上下文, 在一个系统决 定的安全时间中. 它们可能被调度运行多次, 但是 tasklet 调度不累积; ; tasklet 只 运 ...

  8. Linux软中断、tasklet和工作队列

    Linux内核中的软中断.tasklet和工作队列详解 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来 ...

  9. 嵌入式Linux内核tasklet机制(附实测代码)

    Linux 中断编程分为中断顶半部,中断底半部 中断顶半部: 做紧急,耗时短的事情,同时还启动中断底半部. 中断底半部: 做耗时的事件,这个事件在执行过程可以被中断. 中断底半部实现方法: taskl ...

随机推荐

  1. URL编程

    package com.tanlei.URL; import java.io.File; import java.io.FileOutputStream; import java.io.IOExcep ...

  2. PHP来控制Linux,ssh2来控制服务器端

    注意:我们用PHP来控制Linux,php环境可以在windows也可以在linux,但是我们要控制的机器是一台linux(被控制的linux关闭selinux和firewalld). 如果php在l ...

  3. 一个iOS开发者对tvOS SDK的初探

    http://www.cocoachina.com/ios/20151001/13652.html 作者:Chris Wagner原文地址:tvOS SDK: An iOS Developer’s I ...

  4. Leetcode747.Largest Number At Least Twice of Others至少是其他数字两倍的最大数

    在一个给定的数组nums中,总是存在一个最大元素 . 查找数组中的最大元素是否至少是数组中每个其他数字的两倍. 如果是,则返回最大元素的索引,否则返回-1. 示例 1: 输入: nums = [3, ...

  5. PHPCMS快速建站系列之标签循环嵌套

    标签循环嵌套方法,可以实现对PC标签循环调用,代码如下: 在此文件里/phpcms/lib/classes/template_cache.class.php 里的 template_parse 方法里 ...

  6. 易位构词EOJ3451【字符串】【思维题】【模拟】

    http://acm.ecnu.edu.cn/problem/3451/ 官方题解: 我们可以先考虑字符串有序的情况,比如是 aaabcc,我们只要将字符串右移 3 位,变成 bccaaa,就做完了. ...

  7. Run As none applicable

    详解如何在myeclipse中运行JSP,Run As none applicable(图) 内容提要:对JSP的访问都是用浏览器进行的,没有Run on Server这个选项.   在MyEclip ...

  8. oracle表复杂查询--创建数据库实例

    n  创建数据库有两种方法: 1)通过oracle提供的向导工具 2)我们可以用手工步骤直接创建 但我们创建完一个新的数据库实例后,在服务中就会有两个新的服务创建,这时,你根据实际需要去启动相应的数据 ...

  9. Effective C++: 01让自己习惯C++

    01:视C++为一个语言联邦 1:今天的C++已经是个多重范型编程语言(multiparadigm programming language),一个同时支持过程形式(procedural).面向对象形 ...

  10. IP应用加速 – DCDN迈入全栈新篇章

    4月11日,第七届"亚太内容分发大会"暨CDN峰会国际论坛中,阿里云资深技术专家姚伟斌发布了DCDN子产品IP应用加速(IPA).IPA是基于阿里云CDN本身的资源优化,对传输层( ...