随笔- 19  评论- 28  文章- 0 

linux驱动中的工作队列理解

工作队列的作用:用来代替任务队列.

  他们允许内核函数(像可延迟的函数)激活,而且稍后由一种叫做工作者线程的特殊内核线程来执行.

和可延迟函数的不同:

  可延迟函数运行在中断上下文中,不一定在创建它的进程当中运行.

  工作队列中的函数运行在进程上下文中.(但是由内核线程来执行)

  执行可阻塞函数的唯一方式是在进程上下文中运行.

相同点:

  可延迟函数运行时不可能有任何正在运行的进程,而工作队列又是由内核线程来执行的,所以他们都不能访问用户态地址空间.

工作队列的使用.

1.  创建

2.  提交队列

3.  删除

创建:

  创建分为工作队列的创建和工作函数(任务)的创建.

  (1)  工作队列的创建需要有其描述符,它的数据结构是 workqueue_struct.该结构定义在<linux/workqueue.h>中.这里我们不需要关心它的具体组成,内核已经写好了两个两个函数帮我们创建队列:

      struct workqueue_struct *create_workqueue(const char *name);

      struct workqueue_struct * workqueue_singlethread_workqueue(const char *name);

      他们的区别在于实际处理器的多少,如果是单核处理器的话,他们毫无区别.

      因为每个工作队列都有一个或多个(多核处理器)专用的进程(内核线程),这些进程运行提交到该工作队列函数.

      create_workqueue内核会在系统中的每个处理器上为该工作队列创建专用的线程.这样,如果工作队列足够多的话,可能对系统的性能有所杀伤,而create_singlethread_workqueue则只会创建一个专用的线程.所以,如果单个工作线程足够使用,推荐使用第二个函数来创建工作队列.

      同样的,工作任务的创建也需要有其描述符,它的数据结构是work_struct.内核同样为我们创建好了几个宏来方便的创建它.

        DECLARE_WORK(name,void(*function)(void *),void *data);

          用于在内核编译时使用.

        INIT_WORK(struct work_struct *work,void(*function)(void *),void *data);

          用于在系统运行时创建.首次创建时使用它.

        PREPARE_WORK(struct work_struct *work,void(*function)(void *),void *data);

          用于在系统运行时创建.没有INIT_WORK初始化彻底,因为它不会初始化用来将work_struct结构连接到工作队列的指针.如果结构已经被提交到工作队列,而只是需要修改该结构,则应该使用PREPARE_WORK而不是INIT_WORK.

提交:

   如果要将工作提交到工作队列,则可使用如下两个函数之一:

    int queue_work(struct workqueue_struct *queue,struct work_struct *work);

    int queue_delayed_work(struct workqueue_struct *queue,struct work_struct *work,unsigned long delay);

    它们都会将work添加到给定的queue.但是如果使用queue_delayed_work,则实际工作至少会在经过指定的jiffies(由delay指定)之后才会执行.如果工作被成功添加到队列,则上述函数的返回值为1,返回值为非零意味着给定的work_struct结构已经等待在该队列中,从而不能两次加入该队列.

删除:

   结束对工作队列的使用后,可调用下面的函数释放相关资源.

    void destroy_workqueue(struct workqueue_struct *queue);

posted on 2012-08-17 10:20  joseph_伽拉  阅读(...)  评论(...编辑  收藏