工作佇列的使用例子

2021-05-24 09:24:29 字數 3948 閱讀 4726

工作佇列(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工作佇列是一種把工作推後執行的機制。推後的工作交由乙個核心執行緒去執行,因此工作佇列的優勢就在於它允許重新排程甚至睡眠。使用工作佇列的流程 主要有兩種,一種使用核心預設的佇列,一種是我們自己建立乙個工作佇列。對於預設預設的工作佇列,如果工作佇列負載太重,執行效率會很低。下面是自己建立的工作...