歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux工作隊列workqueue實現分析

本文檔的Copyleft歸rosetta所有,使用GPL發布,可以自由拷貝、轉載,轉載時請保持文檔的完整性。
參考資料:《Linux內核設計與實現》第3版 LKD3e、linux-2.6.27

工作隊列子系統是一個用於調用創建內核線程的接口,通過它創建的線程負責執行由內核其它部分排到隊列裡的任務。這些內核線程稱為工作者線程。工作隊列子系統提供了一個缺省的工作都線程來處理工作。一般使用缺省線程即可,但當處理密集型和性能要求嚴格的任務時,創建擁有自己的工作者線程比較好。(引至LKD3e)

        這個接口就是create_workqueue(),它返回一個struct workqueue_struct 結構指針。
        /*
         * The externally visible workqueue abstraction is an array of
         * per-CPU workqueues:
         */
        struct workqueue_struct {
            struct cpu_workqueue_struct *cpu_wq;
            struct list_head list;
            const char *name;
            int singlethread;
            int freezeable;     /* Freeze threads during suspend */
        #ifdef CONFIG_LOCKDEP
            struct lockdep_map lockdep_map;
        #endif
        };

上面注釋:外部可見的工作隊列抽象是由per-CPU的工作隊列組成的數組,這個數組為結構體 cpu_workqueue_struct 。所以每種任務,它有一個自己的工作隊列(struct workqueue_struct ),這個工作隊列如果需要的話會為每個CPU創建對應的工作者線程。也就是說每個CPU,每個工作者線程對應一個cpu_workqueue_struct。

        /*
         * The per-CPU workqueue (if single thread, we always use the first
         * possible cpu).
         */
        struct cpu_workqueue_struct {
       
            spinlock_t lock;
       
            struct list_head worklist;
            wait_queue_head_t more_work;
            struct work_struct *current_work;
       
            struct workqueue_struct *wq;
            struct task_struct *thread;
       
            int run_depth;      /* Detect run_workqueue() recursion depth */
        } ____cacheline_aligned;

        剛才說了,每種任務,它都有一個自己的工作隊列,這種任務的抽象就是為每個CPU創建一個處理這種任務的工作者線程(當然這是需要的情況下,如果不需要則會使用默認的工作者線程events/n,n為CPU編號),那麼這個wq就是關聯到自己的工作隊列workqueue_struct。所有的工作者線程都是用普通的內核線程實現的,由worker_thread()函數完成。
當為一個CPU創建完一個線程後,這個線程執行死循環開始休眠,當有操作插入到隊列時,線程被喚醒並執行。(LKD3e)

        對應的具體工作由work_struct結構:
        struct work_struct {
            atomic_long_t data;
            struct list_head entry;
            work_func_t func;
        };
        由list_head可知,它是個雙向鏈表,每個結點為一個work_struct結構類型。每個CPU上的每種類型的隊列都對應這樣一個鏈表。當一個工作線程被喚醒時,它會執行這個鏈表上的所有工作;工作執行完畢後就從鏈表上先移除相應的work_struct;當鏈表上不再有對象時就繼續休眠。
        總得來說就是每種任務(可以理解成為處理不同數據結構),有一個workqueue_struct。每個CPU有多個工作者線程,
        每個線程處理相應的任務。處理過程最終調用的是func。至於func是怎麼賦值的可參考下面代碼實現。

Copyright © Linux教程網 All Rights Reserved