工作佇列(work queue )是另外一種將工作推後執行的形式.
linux 2.6核心使用了不少工作佇列來處理任務,他在使用上和 tasklet最大的不同是工作佇列的函式可以使用休眠,而tasklet的函式是不允許使用休眠的。
工作佇列的使用又分兩種情況,一種是利用系統共享的工作佇列來新增自己的工作,這種情況處理函式不能消耗太多時間,這樣會影響共享佇列中其他任務的處理;另外一種是建立自己的工作佇列並新增工作。
工作、工作佇列和工作者執行緒
我們把推後執行的任務叫做工作(work),描述它的資料結構為work_struct,這些工作以佇列結構組織成工作佇列(workqueue),其資料結構為workqueue_struct,而工作執行緒就是負責執行工作佇列中的工作。系統預設的工作者執行緒為events,自己也可以建立自己的工作者執行緒。
(一)利用系統共享的工作佇列新增工作:
第一步:宣告或編寫乙個工作處理函式
void my_func();
第二步:建立乙個工作結構體變數,並將處理函式和引數的入口位址賦給這個工作結構體變數
declare_work(my_work,my_func,&data); //編譯時建立名為my_work的結構體變數並把函式入口位址和引數位址賦給它;
如果不想要在編譯時就用declare_work()建立並初始化工作結構體變數,也可以在程式執行時再用init_work()建立
struct work_struct my_work; //建立乙個名為my_work的結構體變數,建立後才能使用init_work()
init_work(&my_work,my_func,&data); //初始化已經建立的my_work,其實就是往這個結構體變數中新增處理函式的入口位址和data的位址,通常在驅動的open函式中完成
第三步:將工作結構體變數新增入系統的共享工作佇列
schedule_work(&my_work); //新增入佇列的工作完成後會自動從佇列中刪除
my_work馬上就會被排程,一旦其所在的處理器上的工作者執行緒被喚醒,它就會被執行。
或有時候並不希望工作馬上就被執行,而是希望它經過一段延遲以後再執行。在這種情況下,可以排程它在指定的時間執行:
schedule_delayed_work(&my_work,tick); //延時tick個滴答後再提交工作
這時,&my_work指向的work_struct直到delay指定的時鐘節拍用完以後才會執行。
(二)建立自己的工作佇列來新增工作
第一步:宣告工作處理函式和乙個指向工作佇列的指標
void my_func();
struct workqueue_struct *p_queue;
第二步:建立自己的工作佇列和工作結構體變數(通常在open函式中完成)
p_queue=create_workqueue("my_queue"); //建立乙個名為my_queue的工作佇列並把工作佇列的入口位址賦給宣告的指標
struct work_struct my_work;
init_work(&my_work,my_func,&data); //建立乙個工作結構體變數並初始化,和第一種情況的方法一樣
第三步:將工作新增入自己建立的工作佇列等待執行
queue_work(p_queue,&my_work);
//作用與schedule_work()類似,不同的是將工作新增入p_queue指標指向的工作佇列而不是系統共享的工作佇列
第四步:刪除自己的工作佇列
destroy_workqueue(p_queue); //一般是在close函式中刪除
(三)工作佇列應用例子1
1,定義工作結構體型別和乙個指向工作佇列的指標
struct akm8976_data ;//定義結構型別
static declare_wait_queue_head(data_ready_wq);
init_waitqueue_head(&data_ready_wq);
2,宣告或編寫乙個工作處理函式
static void akm_work_func(struct work_struct *work)
//處理函式的實現,喚醒工作佇列
3,初始化已經建立的工作結構體變數akm->work
static int akm8976_probe(
struct i2c_client *client, const struct i2c_device_id *id)
4,將工作data->work新增入自己建立的工作佇列等待系統預設的工作者執行緒events執行
static irqreturn_t akm8976_interrupt(int irq, void *dev_id)
//硬體中斷處理函式,schedule_work(&data->work); //data->work馬上就會被排程,一旦其所在的處理器上的工作者執行緒被喚醒,它就會被執行。(系統預設的工作者執行緒events執行工作佇列中的工作data->work)
(四)工作佇列應用例子2
1,定義工作結構體型別
struct ds1374 ;定義結構型別
2,宣告或編寫乙個工作處理函式
static void ds1374_work(struct work_struct *work)
out:
if (!ds1374->exiting)
enable_irq(client->irq);
mutex_unlock(&ds1374->mutex);
}//處理函式的實現,
3,初始化已經建立的工作結構體變數akm->work
static int ds1374_probe(struct i2c_client *client,
const struct i2c_device_id *id)
init_work(&akm->work, akm_work_func); //初始化已經建立的工作結構體變數ds1374->work,其實就是往這個結構體變數中新增處理函式的入口
//為ds1374_work;}
4,將工作data->work新增入自己建立的工作佇列等待系統預設的工作者執行緒events執行
static irqreturn_t ds1374_irq(int irq, void *dev_id)
//硬體中斷處理函式,schedule_work(&ds1374->work); //ds1374->work馬上就會被排程,一旦其所在的處理器上的工作者執行緒被喚醒,它就會被執行。(系統預設的工作者執行緒events執行工作佇列中的工作ds1374->work)
(五)工作佇列例子3(自己的工作佇列)
synaptics_tm1400_i2c_rmi.c
5.1,定義工作結構體型別和乙個指向工作佇列的指標
static struct workqueue_struct *synaptics_wq;//指向工作佇列的指標
struct synaptics_ts_data ;
5.2 ,編寫乙個工作處理函式
static void synaptics_ts_work_func(struct work_struct *work)
5.3,建立自己的工作佇列
static int __devinit synaptics_ts_init(void)
5.4,建立自己的工作結構體變數
static int synaptics_ts_probe(
struct i2c_client *client, const struct i2c_device_id *id)
5.5 將工作新增入自己建立的工作佇列等待執行
//作用與schedule_work()類似,不同的是將工作新增入p_queue指標指向的工作佇列而不是系統共享的工作佇列
static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id)
5.6 刪除自己的工作佇列
static void __exit synaptics_ts_exit(void)
工作佇列的使用例子
工作佇列 work queue 是另外一種將工作推後執行的形式.linux 2.6核心使用了不少工作佇列來處理任務,他在使用上和 tasklet最大的不同是工作佇列的函式可以使用休眠,而tasklet的函式是不允許使用休眠的。工作佇列的使用又分兩種情況,一種是利用系統共享的工作佇列來新增自己的工作,...
使用工作佇列
驅動為需要延遲處理的工作建立一 work struct 結構,該結構即為 工作單元 它還包含一 函式指標 用來處理具體的延遲工作 該工作單元被新增到當前 cpu 的預設工作執行緒 或自定義工作執行緒的工作佇列中等待處理 在某一時刻 工作執行緒被喚醒 它將迴圈處理工作佇列中的每乙個 工作單元 使用系統...
Linux工作佇列的使用
linux工作佇列是一種把工作推後執行的機制。推後的工作交由乙個核心執行緒去執行,因此工作佇列的優勢就在於它允許重新排程甚至睡眠。使用工作佇列的流程 主要有兩種,一種使用核心預設的佇列,一種是我們自己建立乙個工作佇列。對於預設預設的工作佇列,如果工作佇列負載太重,執行效率會很低。下面是自己建立的工作...