![如何使用Linux工作队列workqueue,第1张 如何使用Linux工作队列workqueue,第1张](/aiimages/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Linux%E5%B7%A5%E4%BD%9C%E9%98%9F%E5%88%97workqueue.png)
创建一个per-CPU *编译期间静态创建一个per-CPU DEFINE_PER_CPU(type, name) 创建一个名为name,数据类型为type的per-CPU,比如static DEFINE_PER_CPU(struct sk_buff_head, bs_cpu_queues),此时每个CPU都有一个名叫bs_cpu_queues,数据结构为sk_buff_head的变量副本。每个副本都是在自己的CPU上
工作。 * 动态创建per-CPU,以下代码是内核create_workqueue实现的片断 struct workqueue_struct *__create_workqueue(const char *name, int singlethread) { int cpu, destroy = 0struct workqueue_struct *wqstruct task_struct *pwq = kzalloc(sizeof(*wq), GFP_KERNEL)if (!wq) return NULLwq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct)if (!wq->cpu_wq) { kfree(wq)return NULL} …… }创建一个名为name,数据类型为type的per-CPU,比如static DEFINE_PER_CPU(struct sk_buff_head, bs_cpu_queues),此时每个CPU都有一个名叫bs_cpu_queues,数据结构为sk_buff_head的变量副本。每个副本都是在自己的CPU上工作。Linux 2.6内核使用了不少工作
队列来处理任务,他在使用上和 tasklet最大的不同是工作队列的函数可以使用休眠,而tasklet的函数是不允许使用休眠的。工作队列的使用又分两种情况,一种是利用系统共享的工作队列来添加自己的工作,这种情况处理函数不能消耗太多时间,这样会影响共享队列中其他任务的处理另外一种是创建自己的工作队列并添加工作。第二步:创建一个工作结构体变量,并将处理函数和参数的入口地址赋给这个工作结构体变量如果不想要在编译时就用DECLARE_WORK()创建并初始化工作结构体变量,也可以在程序运行时再用INIT_WORK()创建struct work_struct my_work//创建一个名为my_work的结构体变量,创建后才能使用INIT_WORK()INIT_WORK(&my_work,my_func,&data)//初始化已经创建的my_work,其实就是往这个结构体变量中添加处理函数的入口地址和data的地址,通常在驱动的open函数中完成INIT_WORK(&my_work, my_func, &data)//创建一个工作结构体变量并初始化,和第一种情况的方法一样//作用与schedule_work()类似,不同的是将工作添加入p_queue指针指向的工作队列而不是系统共享的工作队列work queue是一种bottom half,中断处理的后半程,强调的是动态的概念,即work是重点,而queue是其次。wait queue是一种「任务队列」,可以把一些进程放在上面睡眠
等待某个事件,强调静态多一些,重点在queue上,即它就是一个queue,这个queue如何调度,什么时候调度并不重要等待队列在内核中有很多用途,尤其适合用于中断处理,进程同步及定时。这里只说,进程经常必须等待某些事件的发生。例如,等待一个磁盘 *** 作的终止,等待释放系统资源,或者等待时间经过固定的间隔。等待队列实现了在事件上的条件等待,希望等待特定事件的进程把放进合适的等待队列,并放弃控制权。因此。等待队列表示一组睡眠的进程,当某一条件为真时,由内核唤醒进程。等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头,等待队列头是一个类型为wait_queue_head_t的数据结构。等待队列链表的每个元素代表一个睡眠进程,该进程等待某一事件的发生,描述符地址存放在task字段中。然而,要唤醒等待队列中所有的进程有时并不方便。例如,如果两个或多个进程在等待互斥访问某一个要释放的资源,仅唤醒等待队列中一个才有意义。这个进程占有资源,而其他进程继续睡眠可以用DECLARE_WAIT_QUEUE_HEAD(name)宏定义一个新的等待队列,该宏静态地声明和初始化名为name的等待队列头变量。 init_waitqueue_head()函数用于初始化已动态分配的wait queue head变量等待队列可以通过DECLARE_WAITQUEUE()静态创建,也可以用init_waitqueue_head()动态创建。进程放入等待队列并设置成不可执行状态。工作队列,workqueue,它允许内核代码来请求在将来某个时间调用一个函数。用来处理不是很紧急事件的回调方式处理方法.工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是写了一个函数,而现在不想马上执行它,需要在将来某个时刻去执行,那就得用工作队列准没错。如果需要用一个可以重新调度的实体来执行下半部处理,也应该使用工作队列。是唯一能在进程上下文运行的下半部实现的机制。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O *** 作时,都会非常有用。一句话概括:根本就是两个不同的概念,差别很大。
简单的说:
一般来说,线程是windows上的概念,windows区分进程和线程。而在linux上,统一叫进程,进程是完成某项任务所需资源的集合,同时也是linux基本的执行单元。
工作队列是一个等待被执行的任务链表,由专有的线程来调度、执行。很多linux驱动的中断下半部的实现,都是采用工作队列的方式。
作者:陈彬
链接:https://www.zhihu.com/question/20085207/answer/13927301
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
评论列表(0条)