Linux内核:工作队列
来源:互联网 发布:淘宝闪电购 编辑:程序博客网 时间:2024/04/30 15:56
http://blog.csdn.net/jansonzhe/article/details/48858571
在我的上一篇文章Linux内核:中断、软中断、tasklet中,我们已经了解了中断底半部的两种实现方式,即软中断和tasklet微线程。但是这两种方式归根结底都是采用软中断机制的,其根本上还是在中断的上下文中执行,所以这也就要求了采用这两种方式编写中断底半部,不能出现一些可能导致程序休眠或者是延迟的函数(虽然当发生中断嵌套时会生成Ksoftirq线程,但这个是不确定的,所以我们在编写程序时,还是不能采用具有休眠或者延时的函数)。因为这样一种缺陷,所以我们的Linux设计师发明了一种新的将操作延迟的方法,那就是工作队列(workqueue)。由于工作队列是工作在一个内核线程上,因此其工作环境为进程的上下文,从而工作函数可以休眠任意时间。
对于每一个通过队列,内核都会为其创建一个新的内核守护线程,也就是说,每一个工作队列都有唯一的一个内核线程与其对应。工作时,该内核线程就会轮询地执行这个工作队列上所有的工作节点上对应的处理函数(这一点有点像tasklet,只不过现在是在一个线程上执行该工作队列),工作队列由一个workqueue_struct数据结构体描述。
- /*
- * The externally visible workqueue abstraction is an array of
- * per-CPU workqueues:
- */
- struct workqueue_struct {
- unsigned int flags; /* I: WQ_* flags */
- //这个共用体表示该workqueue_struct属于哪个CPU的队列。
- union {
- struct cpu_workqueue_struct __percpu *pcpu;
- struct cpu_workqueue_struct *single;
- unsigned long v;
- } cpu_wq; /* I: cwq's */
- struct list_head list; /* W: list of all workqueues */
- //用来连接work_struct的队列头
- struct mutex flush_mutex; /* protects wq flushing */
- int work_color; /* F: current work color */
- int flush_color; /* F: current flush color */
- atomic_t nr_cwqs_to_flush; /* flush in progress */
- struct wq_flusher *first_flusher; /* F: first flusher */
- struct list_head flusher_queue; /* F: flush waiters */
- struct list_head flusher_overflow; /* F: flush overflow list */
- mayday_mask_t mayday_mask; /* cpus requesting rescue */
- struct worker *rescuer; /* I: rescue worker */
- int saved_max_active; /* W: saved cwq max_active */
- const char *name; /* I: workqueue name */
- #ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
- #endif
- };
与原来的tasklet一样,一个工作队列也是只能工作在一个CPU上面的,即每一个CPU都有一个工作队列。而cpu_workqueue_sruct就是描述该CPU的工作队列的结构体。
- /*
- * The per-CPU workqueue. The lower WORK_STRUCT_FLAG_BITS of
- * work_struct->data are used for flags and thus cwqs need to be
- * aligned at two's power of the number of flag bits.
- */
- struct cpu_workqueue_struct {
- struct global_cwq *gcwq; /* I: the associated gcwq */
- struct workqueue_struct *wq; /* I: the owning workqueue ,指向属于该CPU的workqueue_struct结构体*/
- int work_color; /* L: current color */
- int flush_color; /* L: flushing color */
- int nr_in_flight[WORK_NR_COLORS];
- /* L: nr of in_flight works */
- int nr_active; /* L: nr of active works */
- int max_active; /* L: max active works */
- struct list_head delayed_works; /* L: delayed works */
- };
- struct work_struct {
- atomic_long_t data;
- struct list_head entry; //指向与其相邻的前后两个work_struct
- work_func_t func; //该work_struct节点的处理函数。
- #ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
- #endif
- };
- /**
- * schedule_work - put work task in global workqueue
- * @work: job to be done
- *
- * Returns zero if @work was already on the kernel-global workqueue and
- * non-zero otherwise.
- *
- * This puts a job in the kernel-global workqueue if it was not already
- * queued and leaves it in the same position on the kernel-global
- * workqueue otherwise.
- */
- int schedule_work(struct work_struct *work)
- {
- return queue_work(system_wq, work); //将一个新的work_struct添加进workqueue队列
- }
了解完工作队列的基本操作方法之后呢?下面我要开始讲解如何执行一个工作队列了。前面我们了解到工作队列是由一个内核线程执行的,同时这个内核线程是具有CPU属性的,也就是说每一个CPU都有独属于自己的内核工作线程(当然这个线程需要我们自己创建的,在创建的时候我们也可以指定该内核线程属于哪个CPU。创建的方式后面会讲到)。创建完内核线程之后(这个时候内核线程其实已经被唤醒了,因为在创建内核线程的代码里面有唤醒该线程的函数),当然要执行该内核线程的内核函数,这个函数就是woker_thread,在该函数里面呢,woker_thread主要会调用run_workqueue函数,因为该函数负责执行工作队列里面的work_struct关联的函数。
通常我们如果要在驱动程序中使用工作队列时,一共有两种方式:
- 采用共享工作队列
- 自定义工作队列
采用自定义工作队列
采用共享工作队列会有一个弊端,因为毕竟共享队列采用的是kevent线程,系统里面的其它工作也会使用到该共享队列。如果我们在该工作队列加入太多耗时的程序,无疑会降低系统性能,因此一般在驱动程序中,我们会偏向于使用自定义工作队列,采用自定义工作队列也比较简单,相对于共享工作队列,这里多了一个创建自定义工作的函数,即:create_queue函数(注意这个函数会在每一个CPU上都创建一个一个工作队列和相应的线程,这未免太过于消耗资源,因此我们还可以采用在某一指定的CPU上创建一个工作队列,例如采用create_singlethread_workqueue函数,就会在编号为第一个的CPU上创建内核线程和工作队列。)对于自定义的工作队列,在这里我们不能使用schedule_struct函数将work_struct添加进工作队列了,这是因为schedule_struct函数只能往共享工作队列上添加工作节点(work_struct),所以我们必须要采用queue_work 函数。
- linux 内核 工作队列
- Linux内核工作队列
- Linux内核:工作队列
- Linux 内核工作队列
- Linux内核:工作队列
- linux内核工作队列
- linux内核的工作队列
- tasklet、工作队列 - [linux内核]
- Linux内核机制:工作队列
- 论linux内核工作队列
- Linux内核中的工作队列
- 内核中工作队列(linux工作队列)
- 内核中工作队列(linux工作队列)
- 内核中工作队列(linux工作队列)
- linux内核分析之工作队列
- Linux内核中工作队列的操作
- Linux内核实践之工作队列
- linux内核知识之工作队列(workqueue)
- 网站后台不能添加图片,如果是服务器权限问题,应该如何解决?方法如下
- 欢迎使用CSDN-markdown编辑器
- Maven的安装配置
- GIT相关
- bzoj 2435: [Noi2011]道路修建(DFS)
- Linux内核:工作队列
- jquery 做全选操作,undefined
- 第四周项目二
- Apache Shiro官方构架文档中文翻译
- nmon安装和配置
- C++之 lower_bound And upper_bound And insert
- 正则表达式
- springboot 集成httpclient
- java synchronized(个人)