xml地图|网站地图|网站标签 [设为首页] [加入收藏]

咱俩把推后实践的任务叫做工作(work)

转载

1. 什么是workqueue        Linux中的Workqueue机制正是为了简化内核线程的创导。通过调用workqueue的接口就可以创制根底线程。并且能够依靠当前系统CPU的个数创设线程的数据,使得线程管理的职业能够并行化。workqueue是根本中贯彻轻易而有效的编写制定,他确定简化了内核daemon的成立,方便了客户的编程.

      工作行列(workqueue)是其它蓬蓬勃勃种将专门的学业推后施行的情势.专门的学业行列能够把工作推后,交由五个内核线程去实践,也正是说,那些下半部分得以在经过上下文中施行。最关键的正是干活行列允许被重复调治以至是睡觉。

2. 数据构造      我们把推后执行的职责叫做工作(work),描述它的数据构造为work_struct:

 

  1. struct work_struct {  
  2.     atomic_long_t data;       /*办事处理函数func的参数*/  
  3. #define WORK_STRUCT_PENDING 0        /* T if work item pending execution */  
  4. #define WORK_STRUCT_STATIC 1        /* static initializer (debugobjects) */  
  5. #define WORK_STRUCT_FLAG_MASK (3UL)  
  6. #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)  
  7.     struct list_head entry;        /*接连几天专业的指针*/  
  8.     work_func_t func;              /*行事管理函数*/  
  9. #ifdef CONFIG_LOCKDEP  
  10.     struct lockdep_map lockdep_map;  
  11. #endif  
  12. };  

 

      这么些工作以队列构造协会成专业行列(workqueue),其数据布局为workqueue_struct:

[cpp] view plain copy

 

  1. struct workqueue_struct {  
  2.  struct cpu_workqueue_struct *cpu_wq;  
  3.  struct list_head list;  
  4.  const char *name;   /*workqueue name*/  
  5.  int singlethread;   /*是或不是单线程 - 单线程大家首要推荐第三个CPU -0意味选用默许的劳力线程event*/  
  6.  int freezeable;  /* Freeze threads during suspend */  
  7.  int rt;  
  8. };   

     倘使是四线程,Linux根据当前系统CPU的个数创制cpu_workqueue_struct 其构造体正是:

[cpp] view plain copy

 

  1. truct cpu_workqueue_struct {  
  2.  spinlock_t lock;/*因为工小编线程需求一再的管理连接到其上的行事,所以须要限制爱戴*澳门威尼斯老品牌,/  
  3.  struct list_head worklist;  
  4.  wait_queue_head_t more_work;  
  5.  struct work_struct *current_work; /*当前的work*/  
  6.  struct workqueue_struct *wq;   /*所属的workqueue*/  
  7.  struct task_struct *thread; /*职责的上下文*/  
  8. } ____cacheline_aligned;  

       在该协会重要珍惜了多个职务队列,以致基本线程要求睡眠的等待队列,其它还维护了四个职责上下文,即task_struct。
       三者之间的涉及如下:

威尼斯人老牌娱乐 1

 

3. 创造职业
3.1 创制工作queue
a. create_singlethread_workqueue(name)
        该函数的贯彻机制如下图所示,函数重返二个门类为struct workqueue_struct的指针变量,该指针变量所针对的内部存款和储蓄器地址在函数内部调用kzalloc动态变化。所以driver在不再动用该work queue的动静下调用:

        void destroy_workqueue(struct workqueue_struct *wq卡塔尔(قطر‎来刑释此处的内部存款和储蓄器地址。

 威尼斯人老牌娱乐 2

        图中的cwq是风姿浪漫per-CPU类型的地址空间。对于create_singlethread_workqueue来讲,纵然是对于多CPU系统,内核也只担任创设一个worker_thread内核进度。该内核进度被创建之后,会先定义多少个图中的wait节点,然后在后生可畏循环体中检查cwq中的worklist,假若该队列为空,那么就能够把wait节点参加到cwq中的more_work中,然后休眠在该等待队列中。

        Driver调用queue_work(struct workqueue_struct *wq, struct work_struct *work)向wq中投入专门的学问节点。work会依次加在cwq->worklist所指向的链表中。queue_work向cwq->worklist中投入多少个work节点,同一时候会调用wake_up来唤醒休眠在cwq->more_work上的worker_thread进程。wake_up会先调用wait节点上的autoremove_wake_function函数,然后将wait节点从cwq->more_work中移走。

        worker_thread再一次被调解,起始次拍卖卖cwq->worklist中的全数work节点...当全数work节点管理实现,worker_thread重新将wait节点参与到cwq->more_work,然后重新休眠在该等待队列中央行政机关到Driver调用queue_work...

b. create_workqueue

 威尼斯人老牌娱乐 3

 

 

 

       相对于create_singlethread_workqueue, create_workqueue相同会分配叁个wq的做事行列,不过不一致的地方在于,对于多CPU系统来讲,对每二个CPU,都会为之创立四个per-CPU的cwq布局,对应每三个cwq,都会生成三个新的worker_thread进度。不过当用queue_work向cwq上付出work节点时,是哪个CPU调用该函数,那么便向该CPU对应的cwq上的worklist上加码work节点。

威尼斯人老牌娱乐,c.小结        当顾客调用workqueue的初叶化接口create_workqueue或者create_singlethread_workqueue对workqueue队列进行起头化时,内核就开始为客户分配二个workqueue对象,而且将其链到四个大局的workqueue队列中。然后Linux遵照当下CPU的图景,为workqueue对象分配与CPU个数相像的cpu_workqueue_struct对象,每个cpu_workqueue_struct对象都会存在一条任务队列。紧接着,Linux为每种cpu_workqueue_struct对象分配一个内核thread,即内核daemon去管理各类队列中的任务。至此,客商调用开始化接口将workqueue开首化实现,再次来到workqueue的指针。

        workqueue开头化达成之后,将任务运行的上下文蒙受营造起来了,可是具体还并未有可推行的职务,所以,须求定义具体的work_struct对象。然后将work_struct参加到职务队列中,Linux会唤醒daemon去管理任务。

       上述描述的workqueue内核准现原理能够描述如下:

 威尼斯人老牌娱乐 4

 

威尼斯注册, 

3.2  创立事业        要使用专门的工作行列,首先要做的是成立一些急需推后完结的劳作。能够透过DECLARE_WO奥迪Q7K在编写翻译时静态地建该组织:
       DECLARE_WORK(name,void (*func) (void *), void *data);
      那样就能静态地成立四个名称为name,待试行函数为func,参数为data的work_struct结构。
      同样,也能够在运营时通过指针创立二个行事:
      INIT_WORK(structwork_struct *work, woid(*func) (void *), void *data);

4. 调度
a. schedule_work

       在大许多景况下, 并无需自身树立办事行列,而是只定义职业, 将职业协会挂接到内核预约义的平地风波工作行列中调整, 在kernel/workqueue.c中定义了三个静态全局量的专门的学问队列static struct workqueue_struct *keventd_wq;默许的劳力线程叫做events/n,这里n是微电脑的号子,每一种微电脑对应三个线程。比方,单微处理机的系统唯有events/0那样叁个线程。而双微机的系列就能够多二个events/1线程。
       调整职业组织, 将职业协会丰硕到全局的事件工作行列keventd_wq,调用了queue_work通用模块。对外屏蔽了keventd_wq的接口,客户不要求理解此参数,相当于选取了默许参数。keventd_wq由幼功本人维护,创立,销毁。那样work立刻就能够被调治,风姿洒脱旦其所在的微处理机上的劳力线程被提拔,它就能被施行。

b. schedule_delayed_work(&work,delay);       不时候并不愿意专门的学业随时就被实施,而是愿意它经过风度翩翩段延迟之后再施行。在此种气象下,同有的时候间也得以接受timer来开展缓延长时调解,到期后才由默许的机械漏刻回调函数进行专门的职业注册。延迟delay后,被停车计时器唤醒,将work增多到工作队列wq中。

      专业行列是向来不优先级的,基本据守FIFO的不二等秘书诀实行拍卖。

 5. 示例

[cpp] view plain copy

 

  1. #include <linux/module.h>  
  2. #include <linux/init.h>  
  3. #include <linux/workqueue.h>  
  4.   
  5. static struct workqueue_struct *queue=NULL;  
  6. static struct work_struct   work;  
  7.   
  8. staticvoid work_handler(struct work_struct *data)  
  9. {  
  10.        printk(KERN_ALERT"work handler function.n");  
  11. }  
  12.   
  13. static int __init test_init(void)  
  14. {  
  15.       queue=create_singlethread_workqueue("hello world");/*创制一个单线程的做事行列*/  
  16.       if (!queue)  
  17.             goto err;  
  18.   
  19.        INIT_WORK(&work,work_handler);  
  20.        schedule_work(&work);  
  21.   
  22.       return0;  
  23. err:  
  24.       return-1;  
  25. }  
  26.   
  27. static   void __exit test_exit(void)  
  28. {  
  29.        destroy_workqueue(queue);  
  30. }  
  31. MODULE_LICENSE("GPL");  
  32. module_init(test_init);  
  33. module_exit(test_exit);  

序号


接口函数


说明


1


create_workqueue


用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程。输入参数:


@name:workqueue的名称


2


create_singlethread_workqueue


用于创建workqueue,只创建一个内核线程。输入参数:


@name:workqueue名称


3


destroy_workqueue


释放workqueue队列。输入参数:


@ workqueue_struct:需要释放的workqueue队列指针


4


schedule_work


调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq输入参数:


@ work_struct:具体任务对象指针


5


schedule_delayed_work


延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间,输入参数:


@work_struct:具体任务对象指针


@delay:延迟时间


6


queue_work


调度执行一个指定workqueue中的任务。输入参数:


@ workqueue_struct:指定的workqueue指针


@work_struct:具体任务对象指针


7


queue_delayed_work


延迟调度执行一个指定workqueue中的任务,功能与queue_work类似,输入参数多了一个delay。

转自:

本文由澳门威尼斯老品牌发布于威尼斯注册,转载请注明出处:咱俩把推后实践的任务叫做工作(work)