kthread_create 簡單使用

kthread_create:創建線程。
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.       頭文件

  1. #include <linux/sched.h>   //wake_up_process()  
  2.   
  3. #include <linux/kthread.h> //kthread_create()、kthread_run()  
  4.   
  5. #include <err.h> //IS_ERR()、PTR_ERR()  
2.       實現

2.1創建線程

kernel thread可以用kernel_thread創建,但是在執行函數裏面必須用daemonize釋放資源並掛到init下,還需要用completion等待這一過程的完成。爲了簡化操作kthread_create閃亮登場。

在模塊初始化時,可以進行線程的創建。使用下面的函數和宏定義:

  1. struct task_struct *kthread_create(int (*threadfn)(void *data),  
  2.   
  3.                             void *data,  
  4.   
  5.                             const char namefmt[], ...); 

例如:

  1. static struct task_struct *test_task;  
  2.   
  3. static int test_init_module(void)  
  4.   
  5. {  
  6.   
  7.     int err;  
  8.   
  9.     test_task = kthread_create(test_thread, NULL, "test_task");  
  10.   
  11.     if(IS_ERR(test_task)){  
  12.   
  13.       printk("Unable to start kernel thread./n");  
  14.   
  15.       err = PTR_ERR(test_task);  
  16.   
  17.       test_task = NULL;  
  18.   
  19.       return err;  
  20.   
  21.     }  
  22.   
  23.     wake_up_process(test_task);  
  24.   
  25.     return 0;  
  26.   
  27. }  
  28.   
  29.         module_init(test_init_module);  
2.2線程函數

在線程函數裏,完成所需的業務邏輯工作。主要框架如下所示:

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);

例如:

  1.               static void test_cleanup_module(void)  
  2.   
  3. {  
  4.   
  5.             if(test_task){  
  6.   
  7.                 kthread_stop(test_task);  
  8.   
  9.                 test_task = NULL;  
  10.   
  11.             }  
  12.   
  13. }  
  14.   
  15. module_exit(test_cleanup_module); 
3.       注意事項

   (1)       在調用kthread_stop函數時,線程函數不能已經運行結束。否則,kthread_stop函數會一直進行等待。

(2)       線程函數必須能讓出CPU,以便能運行其他線程。同時線程函數也必須能重新被調度運行。在例子程序中,這是通過schedule_timeout()函數完成的。

  4.性能測試

可以使用top命令來查看線程(包括內核線程)的CPU利用率。命令如下:

       top –p 線程號

可以使用下面命令來查找線程號:

       ps aux|grep 線程名

       注:線程名由kthread_create函數的第三個參數指定。

代碼:

  1. #include <linux/kthread.h>  
  2. #include <linux/module.h>  
  3. #ifndef SLEEP_MILLI_SEC  
  4. #define SLEEP_MILLI_SEC(nMilliSec)\  
  5. do { \  
  6. long timeout = (nMilliSec) * HZ / 1000; \  
  7. while(timeout > 0) \  
  8. { \  
  9. timeout = schedule_timeout(timeout); \  
  10. } \  
  11. }while(0);  
  12. #endif  
  13. static struct task_struct * MyThread = NULL;  
  14. static int MyPrintk(void *data)  
  15. {  
  16. char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);  
  17. memset(mydata,'\0',strlen(data)+1);  
  18. strncpy(mydata,data,strlen(data));  
  19. while(!kthread_should_stop())  
  20. {  
  21. SLEEP_MILLI_SEC(1000);  
  22. printk("%s\n",mydata);  
  23. }  
  24. kfree(mydata);  
  25. return 0;  
  26. }  
  27. static int __init init_kthread(void)  
  28. {  
  29. MyThread = kthread_run(MyPrintk,"hello world","mythread");  
  30. return 0;  
  31. }  
  32. static void __exit exit_kthread(void)  
  33. {  
  34. if(MyThread)  
  35. {  
  36. printk("stop MyThread\n");  
  37. kthread_stop(MyThread);  
  38. }  
  39. }  
  40. module_init(init_kthread);  
  41. module_exit(exit_kthread);  
  42. MODULE_AUTHOR("YaoGang");  
這個內核線程的作用就是每隔一秒打印一個“hello world”
值得一提的是kthread_should_stop函數,我們需要在開啓的線程中嵌入該函數並檢查此函數的返回值,否則kthread_stop是不起作用的

可以使用top命令來查看線程(包括內核線程)的CPU利用率。命令如下:

       top –p線程號

可以使用下面命令來查找線程號:

       ps aux|grep線程名







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章