workqueue作為中斷下半部的一種實現方式,和tasklet不同點在於:
1、workqueue中的工作項的執行是在核心執行緒的上下文中進行的,因此可以執行長時間執行的任務,不會阻塞其他程序的執行。tasklet 在中斷上下文中執行,因此不能執行可能會阻塞的操作或者長時間執行的任務。它們的執行時間應該非常短。
2、workqueue 適用於需要延遲執行且較長時間的任務,具有較低的優先順序和較高的靈活性。tasklet 適用於需要立即執行且執行時間很短的任務,具有較高的優先順序,但數量受限且只能在中斷上下文中執行。
workqueue相關結構體:
1、work_struct:工作佇列中要執行的工作項的結構體。它的定義如下:
struct work_struct { atomic_long_t data; struct list_head entry; work_func_t func; }; // 引數說明 data:傳遞給工作函式的引數。 entry:連結串列節點,用於將工作項連線到工作佇列中。 func:指向實際工作函式的指標。
2、workqueue_struct:工作佇列的結構體,表示一個工作佇列。它的定義如下:
struct workqueue_struct { struct list_head list; const char *name; struct lock_class_key key; struct lockdep_map lockdep_map; }; // 引數說明 list:用於連線所有工作佇列的連結串列節點。 name:工作佇列的名稱。 key:用於鎖的類別關鍵字。 lockdep_map:用於鎖依賴關係的對映。
workqueue相關函式:
1、INIT_WORK:用於初始化工作項結構體。它的原型如下:
void INIT_WORK(struct work_struct *work, work_func_t func); // 引數說明 work:指向要初始化的工作項結構體的指標。 func:指向實際工作函式的指標。
2、schedule_work:用於安排工作項在適當的時候執行。它的原型如下:
bool schedule_work(struct work_struct *work); // 引數說明 work:要安排執行的工作項。
3、flush_workqueue:用於重新整理工作佇列,確保佇列中的所有工作項都被執行完畢。它的原型如下:
int flush_workqueue(struct workqueue_struct *wq); // 引數說明 wq:要重新整理的工作佇列。
4、create_workqueue:用於建立一個新的工作佇列。在較新的核心版本中,該函式已被棄用,可以使用 alloc_workqueue 代替。它的原型如下:
struct workqueue_struct *create_workqueue(const char *name); // 引數說明 name:工作佇列的名稱。
5、alloc_workqueue:用於分配並初始化一個新的工作佇列。它的原型如下:
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active); // 引數說明 fmt:工作佇列名稱的格式字串。 flags:工作佇列的標誌。 max_active:工作佇列中同時執行的最大工作項數。
6、destroy_workqueue:用於銷燬一個工作佇列,並釋放其相關資源。它的原型如下:
void destroy_workqueue(struct workqueue_struct *wq); // 引數說明 wq:要銷燬的工作佇列。
workqueue driver demo如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #define WORK_QUEUE_NAME "my_workqueue" // 定義工作結構體 struct work_struct my_work; // 工作處理函式 void my_work_handler(struct work_struct *work) { printk(KERN_INFO "Executing work handler function\n"); // 在這裡執行下半部處理的任務 } // 定義中斷處理函式 irqreturn_t irq_handler(int irq, void *dev_id) { printk(KERN_INFO "Interrupt handler\n"); // 安排工作佇列執行下半部處理 schedule_work(&my_work); return IRQ_HANDLED; } static int __init my_init(void) { int irq = 1; // 替換為實際的中斷號 // 初始化工作佇列 INIT_WORK(&my_work, my_work_handler); // 註冊中斷處理函式 if (request_irq(irq, irq_handler, IRQF_SHARED, "my_irq_handler", &irq_handler) < 0) { printk(KERN_INFO "Failed to register interrupt handler\n"); return -EFAULT; } printk(KERN_INFO "Interrupt handler registered\n"); return 0; } static void __exit my_exit(void) { int irq = 1; // 替換為實際的中斷號 // 取消註冊中斷處理函式 free_irq(irq, &irq_handler); // 重新整理工作佇列,確保已經執行了所有排隊的工作 flush_workqueue(system_long_wq); printk(KERN_INFO "Interrupt handler unregistered\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lethe1203");