struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
線程創建後,不會馬上運行,而是需要將kthread_create() 返回的task_struct指針傳給wake_up_process(),然後通過此函數運行線程。
kthread_run :創建並啓動線程的函數:
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
kthread_stop:通過發送信號給線程,使之退出。
int kthread_stop(struct task_struct *thread);
線程一旦啓動起來後,會一直運行,除非該線程主動調用do_exit函數,或者其他的進程調用kthread_stop函數,結束線程的運行。
但如果線程函數正在處理一個非常重要的任務,它不會被中斷的。當然如果線程函數永遠不返回並且不檢查信號,它將永遠都不會停止。
1. 頭文件
- #include <linux/sched.h> //wake_up_process()
- #include <linux/kthread.h> //kthread_create()、kthread_run()
- #include <err.h> //IS_ERR()、PTR_ERR()
2.1創建線程
kernel
thread可以用kernel_thread創建,但是在執行函數裏面必須用daemonize釋放資源並掛到init下,還需要用completion等待這一過程的完成。爲了簡化操作kthread_create閃亮登場。
在模塊初始化時,可以進行線程的創建。使用下面的函數和宏定義:
- struct task_struct *kthread_create(int (*threadfn)(void *data),
- void *data,
- const char namefmt[], ...);
例如:
- static struct task_struct *test_task;
- static int test_init_module(void)
- {
- int err;
- test_task = kthread_create(test_thread, NULL, "test_task");
- if(IS_ERR(test_task)){
- printk("Unable to start kernel thread./n");
- err = PTR_ERR(test_task);
- test_task = NULL;
- return err;
- }
- wake_up_process(test_task);
- return 0;
- }
- module_init(test_init_module);
在線程函數裏,完成所需的業務邏輯工作。主要框架如下所示:
int threadfunc(void *data){
…
while(1){
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop()) break;
if(){//條件爲真
//進行業務處理
}
else{//條件爲假
//讓出CPU運行其他線程,並在指定的時間內重新被調度
schedule_timeout(HZ);
}
}
…
return 0;
}
2.3結束線程
在模塊卸載時,可以結束線程的運行。使用下面的函數:
int kthread_stop(struct task_struct *k);
例如:
- static void test_cleanup_module(void)
- {
- if(test_task){
- kthread_stop(test_task);
- test_task = NULL;
- }
- }
- module_exit(test_cleanup_module);
(1) 在調用kthread_stop函數時,線程函數不能已經運行結束。否則,kthread_stop函數會一直進行等待。
(2) 線程函數必須能讓出CPU,以便能運行其他線程。同時線程函數也必須能重新被調度運行。在例子程序中,這是通過schedule_timeout()函數完成的。
4.性能測試
可以使用top命令來查看線程(包括內核線程)的CPU利用率。命令如下:
top –p 線程號
可以使用下面命令來查找線程號:
ps aux|grep 線程名
注:線程名由kthread_create函數的第三個參數指定。
代碼:
- #include <linux/kthread.h>
- #include <linux/module.h>
- #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 * MyThread = NULL;
- static int MyPrintk(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 init_kthread(void)
- {
- MyThread = kthread_run(MyPrintk,"hello world","mythread");
- return 0;
- }
- static void __exit exit_kthread(void)
- {
- if(MyThread)
- {
- printk("stop MyThread\n");
- kthread_stop(MyThread);
- }
- }
- module_init(init_kthread);
- module_exit(exit_kthread);
- MODULE_AUTHOR("YaoGang");
值得一提的是kthread_should_stop函數,我們需要在開啓的線程中嵌入該函數並檢查此函數的返回值,否則kthread_stop是不起作用的
可以使用top命令來查看線程(包括內核線程)的CPU利用率。命令如下:
top –p線程號
可以使用下面命令來查找線程號:
ps aux|grep線程名