4.2 内核工作队列原理汇总

来源:互联网 发布:ubuntu原版和麒麟 编辑:程序博客网 时间:2024/05/29 03:17

4.2 kernel 工作队列分析

首先,看看如何使用一个工作队列

#此程序源于网络并稍微做了修改

#myworkqueue.c

include <linux/module.h>

#include <linux/workqueue.h>

#include <linux/slab.h>

 

MODULE_LICENSE("GPL");

 

static struct workqueue_struct *my_wq;

 

typedef struct {

 struct work_struct my_work;

 int    x;

} my_work_t;

 

my_work_t *work, *work2;

 

 

static void my_wq_function( structwork_struct *work)

{

 my_work_t *my_work = (my_work_t *)work;

 printk( "my_work.x %d\n", my_work->x );

 kfree( (void *)work );

 return;

}

 

int init_module( void )

{

  intret;

 my_wq = create_workqueue("my_queue");

  if(my_wq) {

   /* Queue some work (item 1) */

   work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);

   if (work) {

     INIT_WORK( (struct work_struct *)work, my_wq_function );

     work->x = 1;

     ret = queue_work( my_wq, (struct work_struct *)work );

    }

 

   /* Queue some additional work (item 2) */

   work2 = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);

   if (work2) {

     INIT_WORK( (struct work_struct *)work2, my_wq_function );

     work2->x = 2;

     ret = queue_work( my_wq, (struct work_struct *)work2 );

    }

  }

 

 return 0;

}

 

void cleanup_module( void )

{

 flush_workqueue( my_wq );

 destroy_workqueue( my_wq );

 

 return;

}

#Makefile

bj-m:=myworkqueue.o

 

CURRENT_PATH := $(shell pwd)

KERNEL_VERSION := $(shell uname -r)

#KERNEL_HEADER_DIR :=/usr/src/$(LINUX_KERNELKERNEL_VERSION)

KERNELDIR ?= /lib/modules/$(shell uname-r)/build

all:

       make -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:

       make -C $(KERNELDIR) M=$(CURRENT_PATH) clean

pc#insmod myworkqueue.ko

[ 7393.374386] my_work.x 1

[ 7393.374392] my_work.x 2

 

在4.2的kernel里工作队列的组织形式已经发生了变化,之前的工作的组织形式如下:

                                                                   之前队列行为图

 

从上图可知,之前内核工作队列的机制是,每分配一个队列,都会有对应在每个核上分配一个本地的线程,用于并发处理工作队列上的各个work。

在新的内核组织形式如下:


从上图可以看出,新的工作队列的(BOUND类型)原理如下:

1.        工作队列和工作者线程已经分开,工作者线程用work_pool的数据结构来管理,每个逻辑的cpu上都有两个本地的work_pool,一个是高优先级的,一个是普通优先级的。

2.        每创建一个工作队列,此工作队列会分配一个per-cpu的变量pwq,这个变量指向每个cpu的work_pool

3.        当程序调用queue_work将一个work插入队列时,它会将work插入queue_work这个函数运行的cpu上的work_pool中的work_list上

4.        Work_pool中有用于管理的线程,这个线程根据本cpu上的忙闲程度,会增加和减少kworker的数量,而不是由之前内核,根据工作队列的数量决定的

5.        Work_pool有高优先级(kworker:H)和正常优先级(kworer),这个目的是为了让高优先级的任务得到优先执行

 

新旧工作队列机制的区别:

从上面可知,旧的机制是每创建一个工作队列的同时,都会创建一个本地cpu上的工作者线程,而新的机制是用工作者池(worker_pool)来根据本cpu上的work的忙闲程度来增加和减少工作者线程的数量。这么做的原因是之前的方案并不能在并发上有什么优势并且由于每建立一个工作队列都要在每个cpu上建立一个本地工作者线程,这样的话一是线程太多,导致内核调度开销增大。二是每个线程都要占用比较大的内存,因为每个线程有一个task_struct的超级大的结构体。


总结写到这里,后续要做代码级别的分析。

0 0
原创粉丝点击