天天看點

linux work queue

工作隊列(work queue)是Linux kernel中将工作推後執行的一種機制。這種機制和BH或Tasklets不同之處在于工作隊列是把推後的工作交由一個核心線程去執行,是以工作隊列的優勢就在于它允許重新排程甚至睡眠。

每個工作隊列有一個專門的線程,所有來自運作隊列的任 務在程序的上下文中運作(這樣它們可以休眠)。驅動程式可以建立并使用它們自己的工作隊列,或者使用核心的一個工作隊列。

工作隊列的資料結構:

work_struct

結構體:

struct work_struct {
    atomic_long_t data;  //用來存儲使用者的私人資料,此資料即是func的參數
    struct list_head entry; //循環連結清單結構;
    work_func_t func;  //函數指針,由使用者實作;
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};
           

delayed_work結構體:

struct delayed_work {
    struct work_struct work;
    struct timer_list timer;

    /* target workqueue and CPU ->timer uses to queue ->work */
    struct workqueue_struct *wq;
    int cpu;
};
           

初始化指定工作,目的是把使用者指定的函數_func

#define INIT_WORK(_work, _func)                     \
__INIT_WORK((_work), (_func), 0)

#define INIT_DELAYED_WORK(_work, _func)                 \
__INIT_DELAYED_WORK(_work, _func, 0)
           

對工作進行排程,即把給定工作的處理函數送出給預設的工作隊列和工作者線程。工作者線程本質上是一個普通的核心線程,在預設情況下,每個CPU均有一個類型為“events”的工作者線程,當調用schedule_work時,這個工作者線程會被喚醒去執行工作連結清單上的所有工作。

static inline bool schedule_work(struct work_struct *work)
static inline bool schedule_delayed_work(struct delayed_work *dwork,
                 unsigned long delay)
           

重新整理預設工作隊列。此函數會一直等待,直到隊列中的所有工作都被執行。

static inline void flush_scheduled_work(void)
           

flush_scheduled_work

并不取消任何延遲執行的工作,是以,如果要取消延遲工作,應該調用

cancel_delayed_work

bool cancel_delayed_work(struct delayed_work *dwork) 
           

以上均是采用預設工作者線程來實作工作隊列,其優點是簡單易用,缺點是如果預設工作隊列負載太重,執行效率會很低,這就需要我們建立自己的工作者線程和工作隊列。

工作隊列結構體:

/*
 * The externally visible workqueue.  It relays the issued work items to
 * the appropriate worker_pool through its pool_workqueues.
 */
struct workqueue_struct {
    struct list_head    pwqs;       /* WR: all pwqs of this wq */
    struct list_head    list;       /* PR: list of all workqueues */

    struct mutex        mutex;      /* protects this wq */
    int         work_color; /* WQ: current work color */
    int         flush_color;    /* WQ: current flush color */
    atomic_t        nr_pwqs_to_flush; /* flush in progress */
    struct wq_flusher   *first_flusher; /* WQ: first flusher */
    struct list_head    flusher_queue;  /* WQ: flush waiters */
    struct list_head    flusher_overflow; /* WQ: flush overflow list */

    struct list_head    maydays;    /* MD: pwqs requesting rescue */
    struct worker       *rescuer;   /* I: rescue worker */

    int         nr_drainers;    /* WQ: drain in progress */
    int         saved_max_active; /* WQ: saved pwq max_active */

    struct workqueue_attrs  *unbound_attrs; /* PW: only for unbound wqs */
    struct pool_workqueue   *dfl_pwq;   /* PW: only for unbound wqs */

#ifdef CONFIG_SYSFS
    struct wq_device    *wq_dev;    /* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
    struct lockdep_map  lockdep_map;
#endif
    char            name[WQ_NAME_LEN]; /* I: workqueue name */

    /*
     * Destruction of workqueue_struct is sched-RCU protected to allow
     * walking the workqueues list without grabbing wq_pool_mutex.
     * This is used to dump all workqueues from sysrq.
     */
    struct rcu_head     rcu;

    /* hot fields used during command issue, aligned to cacheline */
    unsigned int        flags ____cacheline_aligned; /* WQ: WQ_* flags */
    struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
    struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */
};
           

建立新的工作隊列和相應的工作者線程,name用于該核心線程的命名。

#define create_workqueue(name)                      \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
           

類似于

schedule_work

,差別在于

queue_work

把給定工作送出給建立的工作隊列wq而不是預設隊列。

static inline bool queue_work(struct workqueue_struct *wq,
              struct work_struct *work)
           

延遲執行工作:

static inline bool queue_delayed_work(struct workqueue_struct *wq,
                  struct delayed_work *dwork,
                  unsigned long delay)
           

重新整理指定工作隊列。

void flush_workqueue(struct workqueue_struct *wq)
           

示例:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>

static struct workqueue_struct *queue=NULL;
static struct work_struct   work;

staticvoid work_handler(struct work_struct *data)
{
       printk(KERN_ALERT"work handler function.\n");
}

static int __init test_init(void)
{
      queue=create_singlethread_workqueue("hello world");/*建立一個單線程的工作隊列*/
      if (!queue)
            goto err;

       INIT_WORK(&work,work_handler);
       schedule_work(&work);

      return0;
err:
      return-;
}

static   void __exit test_exit(void)
{
       destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

           

繼續閱讀