核心執行緒的建立、使用和退出;關於延時巨集的補充說明
相關函式:
kthread_create():建立核心執行緒
struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...);
kernel thread可以用kernel_thread建立,但是在執行函式裡面必須用daemonize釋放資源並掛到init下,還需要用completion等待這一過程的完成。為了簡化操作,定義了kthread_create。
執行緒建立後,不會馬上執行,而是需要將kthread_create() 返回的task_struct指標傳給wake_up_process(),然後通過此函式執行執行緒。
kthread_run():建立並啟動執行緒的函式。
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
它實際上是個巨集,由kthread_create()和wake_up_process()組成。
#define kthread_run(threadfn, data, namefmt, ...) / ({/ struct task_struct *__k / = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); / if (!IS_ERR(__k)) / wake_up_process(__k); / __k;/ })
kthread_stop():通過傳送訊號給執行緒,使之退出。
int kthread_stop(struct task_struct *thread);
執行緒一旦啟動起來後,會一直執行,除非該執行緒主動呼叫do_exit函式,或者其他的程序呼叫kthread_stop函式,結束執行緒的執行。
但如果執行緒函式正在處理一個非常重要的任務,它不會被中斷的。當然如果執行緒函式永遠不返回並且不檢查訊號,它將永遠都不會停止。
同時,在呼叫kthread_stop函式時,執行緒函式不能已經執行結束。否則,kthread_stop函式會一直進行等待。
核心執行緒的一般框架
int threadfunc(void *data){
…
while(1){
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop()) break;
if(){//條件為真
//進行業務處理
}
else{//條件為假
//讓出CPU執行其他執行緒,並在指定的時間內重新被排程
schedule_timeout(HZ);
}
}
…
return 0;
}
執行緒相關測試命令
可以使用top命令來檢視執行緒(包括核心執行緒)的CPU利用率。命令如下:
top –p 執行緒號
可以使用下面命令來查詢執行緒號:
ps aux|grep 執行緒名
示例程式:使用模組載入核心執行緒,實現每1s在核心中列印字元。
(makefile略去,和以前一篇博文一樣的寫法。)
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_create(),kthread_run() #include <linux/err.h> //IS_ERR(),PTR_ERR() #ifndef SLEEP_MILLI_SEC #define SLEEP_MILLI_SEC(nMilliSec)\ do { \ long timeout = (nMilliSec) * HZ / 1000; \ while(timeout > 0) \ { \ timeout = schedule_timeout(timeout); \ } \ }while(0); #endif static struct task_struct *my_task = NULL; static int my_kthread(void *data) { char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL); memset(mydata,'\0',strlen(data)+1); strncpy(mydata,data,strlen(data)); while(!kthread_should_stop()) { SLEEP_MILLI_SEC(1000); printk("%s\n",mydata); } kfree(mydata); return 0; } static int __init kernel_thread_init(void) { int err; printk(KERN_ALERT "Kernel thread initalizing...\n"); my_task = kthread_create(my_kthread,"hello world","mythread"); if(IS_ERR(my_task)){ printk("Unable to start kernel thread./n"); err = PTR_ERR(my_task); my_task = NULL; return err; } wake_up_process(my_task); return 0; } static void __exit kernel_thread_exit(void) { if(my_task){ printk(KERN_ALERT "Cancel this kernel thread.\n"); kthread_stop(my_task); printk(KERN_ALERT "Canceled.\n"); } } module_init(kernel_thread_init); module_exit(kernel_thread_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("anonymous");
補充說明:
這個延時巨集在一些情況下會造成核心執行緒CPU佔用率過高的情況。根據對schedule_timeout()原始碼的分析,它只是週期使執行緒成為TASK_RUNNING狀態,這個執行緒並沒有真正的睡眠。解決辦法:在while迴圈中的起始處加入set_current_state(TASK_INTERRUPTIBLE)即可。