Linux Kernel Completion 使用指南
在Linux內核編程中,completion是一個用于進程同步的機制,常用于等待某個事件的完成。它提供了一種簡單的方式,讓一個線程等待另一個線程完成某項任務。
基本使用方法
初始化
completion結構需要在使用之前進行初始化,可以使用以下兩種方式之一:
- 靜態初始化:
DECLARE_COMPLETION(my_completion);
- 動態初始化:
struct completion my_completion;
init_completion(&my_completion);
等待事件
一個線程可以調用wait_for_completion
或其變種來等待事件的完成:
wait_for_completion(&my_completion);
變種方法包括:
wait_for_completion_timeout(&my_completion, timeout)
:帶超時的等待。wait_for_completion_interruptible(&my_completion)
:可以被中斷的等待。wait_for_completion_killable(&my_completion)
:可以被kill信號中斷的等待。
觸發事件
當某個事件完成時,應該調用complete
函數來喚醒等待的線程:
complete(&my_completion);
如果有多個等待者,并且你希望喚醒所有等待者,可以使用complete_all
:
complete_all(&my_completion);
高級使用方法
重新初始化
在某些情況下,一個completion結構可能需要重復使用,這時可以使用reinit_completion
重新初始化:
reinit_completion(&my_completion);
超時等待
為了避免無限期等待,可以使用帶超時的等待函數,例如:
unsigned long timeout = msecs_to_jiffies(500); // 500 ms
wait_for_completion_timeout(&my_completion, timeout);
可中斷的等待
有時需要等待可以被中斷,可以使用wait_for_completion_interruptible
或wait_for_completion_killable
:
int ret;
ret = wait_for_completion_interruptible(&my_completion);
if (ret == -ERESTARTSYS) {// 等待被信號中斷
}
注意事項
- 初始化問題:確保在使用completion之前正確初始化,避免使用未初始化的completion。
- 重入問題:避免對同一個completion結構多次調用
complete
,因為這會導致不可預測的行為。 - 超時處理:合理使用超時等待,避免線程無限期掛起。
- 中斷安全:在中斷上下文中不能使用可能導致睡眠的函數,例如等待函數。
- 資源釋放:在模塊卸載或資源釋放時,確保沒有線程在等待,避免資源泄漏或訪問非法內存。
代碼示例
以下是一個簡單的例子,展示了一個線程等待另一個線程完成某項任務:
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/delay.h>static struct completion my_completion;int worker_thread(void *data) {printk(KERN_INFO "Worker thread: Starting work\n");msleep(5000); // 模擬工作printk(KERN_INFO "Worker thread: Work done, signaling completion\n");complete(&my_completion);return 0;
}static int __init my_module_init(void) {struct task_struct *task;init_completion(&my_completion);task = kthread_run(worker_thread, NULL, "worker_thread");if (IS_ERR(task)) {printk(KERN_ERR "Failed to create worker thread\n");return PTR_ERR(task);}printk(KERN_INFO "Main thread: Waiting for completion\n");wait_for_completion(&my_completion);printk(KERN_INFO "Main thread: Detected completion\n");return 0;
}static void __exit my_module_exit(void) {printk(KERN_INFO "Module exit\n");
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
這個例子創建了一個工作線程,該線程在完成工作后調用complete
。主線程等待工作線程完成后繼續執行。
總結
Linux內核中的completion機制是一個強大的工具,用于線程間的同步。通過合理使用它,可以有效地控制線程的執行順序,確保程序的正確性。在使用時,應注意初始化、超時、中斷安全等問題,以避免潛在的bug。