linux work queue & work struct解析
2013-01-25 18:13
344 查看
工作队列是, 表面上看, 类似于 taskets; 它们允许内核代码来请求在将来某个时间调用一个函数. 但是, 有几个显著的不同在这 2 个之间, 包括:
tasklet 在软件中断上下文中运行的结果是所有的 tasklet 代码必须是原子的. 相反, 工作队列函数在一个特殊内核进程上下文运行; 结果, 它们有更多的灵活性. 特别地, 工作队列函数能够睡眠.
tasklet 常常在它们最初被提交的处理器上运行. 工作队列以相同地方式工作, 缺省地.
内核代码可以请求工作队列函数被延后一个明确的时间间隔.
两者之间关键的不同是 tasklet 执行的很快, 短时期, 并且在原子态, 而工作队列函数可能有高周期但是不需要是原子的. 每个机制有它适合的情形.
工作队列有一个 struct workqueue_struct 类型, 在 <linux/workqueue.h> 中定义. 一个工作队列必须明确的在使用前创建, 使用一个下列的 2 个函数:
每个工作队列有一个或多个专用的进程("内核线程"), 它运行提交给这个队列的函数. 如果你使用 create_workqueue, 你得到一个工作队列它有一个专用的线程在系统的每个处理器上. 在很多情况下, 所有这些线程是简单的过度行为; 如果一个单个工作者线程就足够, 使用 create_singlethread_workqueue 来代替创建工作队列
提交一个任务给一个工作队列, 你需要填充一个 work_struct 结构. 这可以在编译时完成, 如下:
这里 name 是声明的结构名称, function 是从工作队列被调用的函数, 以及 data 是一个传递给这个函数的值. 如果你需要建立 work_struct 结构在运行时, 使用下面 2 个宏定义:
INIT_WORK 做更加全面的初始化结构的工作; 你应当在第一次建立结构时使用它. PREPARE_WORK 做几乎同样的工作, 但是它不初始化用来连接 work_struct 结构到工作队列的指针. 如果有任何的可能性这个结构当前被提交给一个工作队列, 并且你需要改变这个队列, 使用 PREPARE_WORK 而不是 INIT_WORK.
有 2 个函数来提交工作给一个工作队列:
每个都添加工作到给定的队列. 如果使用 queue_delay_work, 但是, 实际的工作没有进行直到至少 delay jiffies 已过去. 从这些函数的返回值是 0 如果工作被成功加入到队列; 一个非零结果意味着这个 work_struct 结构已经在队列中等待, 并且第 2 次没有加入.
在将来的某个时间, 这个工作函数将被使用给定的 data 值来调用. 这个函数将在工作者线程的上下文运行, 因此它可以睡眠如果需要 -- 尽管你应当知道这个睡眠可能怎样影响提交给同一个工作队列的其他任务. 这个函数不能做的是, 但是, 是存取用户空间. 因为它在一个内核线程中运行, 完全没有用户空间来存取.
如果你需要取消一个挂起的工作队列入口, 你可以调用:
返回值是非零如果这个入口在它开始执行前被取消. 内核保证给定入口的执行不会在调用 cancel_delay_work 后被初始化. 如果 cancel_delay_work 返回 0, 但是, 这个入口可能已经运行在一个不同的处理器, 并且可能仍然在调用 cancel_delayed_work 后在运行. 要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行, 你必须跟随这个调用来调用:
在 flush_workqueue 返回后, 没有在这个调用前提交的函数在系统中任何地方运行.
当你用完一个工作队列, 你可以去掉它, 使用:
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 workqueue 原理解析
- Linux workqueue_struct 前后版本的比较
- Linux&nbsp;__setup解析
- (十一)洞悉linux下的Netfilter&iptables:iptables命令行工具源码解析【上】
- STL源码解析-04序列容器-05heep&priority_queue
- 洞悉linux下的Netfilter&iptables:iptables命令行工具源码解析【上】
- Linux的中断处理:work_struct的使用实例
- (十一)洞悉linux下的Netfilter&iptables:iptables命令行工具源码解析【上】
- linux 输入参数利用getopt、struct option、getopt_long、getopt_long_only解析
- linux workqueue
- Linux发送函数dev_queue_xmit分析&amp;…
- error LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __thiscall Widget::metaObject
- linux启动第一个应用程序init && init启动android过程解析 && init.rc与inittab的关系 && android property和linux 环境变量
- Linux work queue工作队列小结与使用
- 解析Android消息处理机制:Handler/Thread/Looper & MessageQueue
- qwt 无法解析的外部符号 "public: static struct QMetaObject const QwtPlot::staticMetaObject
- 洞悉linux下的Netfilter&iptables:iptables命令行工具源码解析【下】
- (十一)洞悉linux下的Netfilter&iptables:iptables命令行工具源码解析【上】
- 解析 Linux 内核可装载模块的版本…
- linux bash Shell脚本经典之Fork炸弹解析:() { :|:& };: