工作隊列的作用:用來代替任務隊列.
他們允許內核函數(像可延遲的函數)激活,而且稍后由一種叫做工作者線程的特殊內核線程來執行.
和可延遲函數的不同:
可延遲函數運行在中斷上下文中,不一定在創建它的進程當中運行.
工作隊列中的函數運行在進程上下文中.(但是由內核線程來執行)
執行可阻塞函數的唯一方式是在進程上下文中運行.
相同點:
可延遲函數運行時不可能有任何正在運行的進程,而工作隊列又是由內核線程來執行的,所以他們都不能訪問用戶態地址空間.
工作隊列的使用.
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);