Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1165394
  • 博文数量: 134
  • 博客积分: 2488
  • 博客等级: 大尉
  • 技术积分: 7554
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-26 21:19
  • 认证徽章:
个人简介

1.每日自省; 2.享受人生; 3.尽力而为; 4.坚持不懈; 5.切莫急躁; 6.慎言敏行; 7.动心忍性; 8.上善若水。

文章分类

全部博文(134)

文章存档

2014年(38)

2013年(42)

2012年(15)

2011年(39)

分类: LINUX

2014-03-26 14:54:29

      工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制。

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

        每个工作队列多有一个数组,数据元素的数目与内核处理器core的数目相同,每个数据元素都列出来将要延期执行的任务。

        对于每个工作队列来说,内核都会创建一个新的内核守护线程,延期任务使用上下文描述的等待队列机制,在守护进程的上下午执行。

先定义几个内核中使用工作队列时用到的术语方便后面描述。

  • workqueues:所有工作项被 ( 需要被执行的工作 ) 排列于该队列,因此称作工作队列 (workqueues) 。
  • worker thread:工作者线程 (worker thread) 是一个用于执行工作队列中各个工作项的内核线程,当工作队列中没有工作项时,该线程将变为 idle 状态。
  • single threaded(ST)::工作者线程的表现形式之一,在系统范围内,只有一个工作者线程为工作队列服务
  • multi threaded(MT):工作者线程的表现形式之一,在多 CPU 系统上每个 CPU 上都有一个工作者线程为工作队列服务

如何使用工作队列哪?按如下步骤:

一.       声明一个工作队列

staticstruct workqueue_struct *test_wq;

二.       声明一个延期工作描述实例

static struct delayed_work test_dwq;

三.       声明并实现一个工作队列延迟处理函数

voiddelay_func(struct work_struct *work);

voiddelay_func(struct work_struct *work)

{

    printk(KERN_INFO "My name isdelay_func!\n");

}

四.       初始化一个工作队列

test_wq = create_workqueue("test_wq");

五.       任务初始化

INIT_DELAYED_WORK(&test_dwq,delay_func);

六.       向工作队列提交工作项

queue_delayed_work(test_wq, &test_dwq, delay);

七.       取消工作队列中的工作项

int cancel_delayed_work(test_wq);

       如果这个工作项在它开始执行前被取消,返回值是非零。内核保证给定工作项的执行不会在调用 cancel_delay_work 成功后被执行。 如果 cancel_delay_work 返回 0,则这个工作项可能已经运行在一个不同的处理器,并且仍然可能在调用 cancel_delayed_work 之后被执行。要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行,你必须跟随这个调用之后接着调用 flush_workqueue。在 flush_workqueue 返回后。任何在改调用之前提交的工作函数都不会在系统任何地方运行。

八.       刷新工作队列

flush_workqueue(test_wq);


九.       工作队列销毁

destroy_workqueue(test_wq);

 

涉及到的主要函数与结构体

一.       函数queue_delayed_work()

函数queue_delayed_work()是用于向工作队列提交delayed_work实例,确保在延期执行之前,至少会经过由delay指定的一段时间(以jiffies为单位)。

该函数首先创建一个由内核定时器,该定时器将在delayed jiffies之内超时。

二.       延期工作描述实例

structdelayed_work {

       struct work_struct work; /* 将作为实例被queue_work或queue_work_delayed添加到一个工作队列*/

       struct timer_list timer; /* 延迟时间*/

};

三.       alloc_workqueue函数

struct workqueue_struct *alloc_workqueue(char *name, unsigned intflags, int max_active);

name:为工作队列的名字,而不像 2.6.36 之前实际是为工作队列服务的内核线程的名字。

Flag: 指明工作队列的属性,可以设定的标记如下:

  • WQ_NON_REENTRANT:默认情况下,工作队列只是确保在同一 CPU 上不可重入,即工作项不能在同一 CPU 上被多个工作者线程并发执行,但容许在多个 CPU 上并发执行。但该标志标明在多个 CPU 上也是不可重入的,工作项将在一个不可重入工作队列中排队,并确保至多在一个系统范围内的工作者线程被执行。
  • WQ_UNBOUND:工作项被放入一个由特定 gcwq 服务的未限定工作队列,该客户工作者线程没有被限定到特定的 CPU,这样,未限定工作者队列就像简单的执行上下文一般,没有并发管理。未限定的 gcwq 试图尽可能快的执行工作项。
  • WQ_FREEZEABLE:可冻结 wq 参与系统的暂停操作。该工作队列的工作项将被暂停,除非被唤醒,否者没有新的工作项被执行。
  • WQ_MEM_RECLAIM:所有的工作队列可能在内存回收路径上被使用。使用该标志则保证至少有一个执行上下文而不管在任何内存压力之下。
  • WQ_HIGHPRI:高优先级的工作项将被排练在队列头上,并且执行时不考虑并发级别;换句话说,只要资源可用,高优先级的工作项将尽可能快的执行。高优先工作项之间依据提交的顺序被执行。

·         WQ_CPU_INTENSIVE:CPU 密集的工作项对并发级别并无贡献,换句话说,可运行的 CPU密集型工作项将不阻止其它工作项。这对于限定得工作项非常有用,因为它期望更多的 CPU 时钟周期,所以将它们的执行调度交给系统调度器。

·         WQ_DRAINING:internal: workqueue is draining

·         WQ_RESCUER :internal: workqueue has rescuer

·         WQ_MAX_ACTIVE: I like 512, better ideas?

·         WQ_MAX_UNBOUND_PER_CPU: 4 * #cpus for unbound wq

·         WQ_DFL_ACTIVE:等于WQ_MAX_ACTIVE / 2,

max_active:决定了一个 wq 在 per-CPU 上能执行的最大工作项。比如 max_active 设置为 16 表示一个工作队列上最多 16 个工作项能同时在 per-CPU 上同时执行。当前实行中,对所有限定工作队列,max_active 的最大值是 512,而设定为 0 时表示是 256;而对于未限定工作队列,该最大值为:MAX[512,4 * num_possible_cpus() ],除非有特别的理由需要限流或者其它原因,一般设定为 0 就可以了

实例


阅读(9844) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册