linux驱动开发之内核线程
內核經常需要在后臺執行一些操作,這種任務就可以通過內核線程(kernle thread)完成--獨立運行在內核空間的標準進程。內核線程和普通的進程間的區別在于內核線程沒有獨立的地址空間,mm指針被設置為NULL;它只在 內核空間運行,從來不切換到用戶空間去;并且和普通進程一樣,可以被調度,也可以被搶占。實際上,內核線程只能由其他內核線程創建,在現有的內核線程中創建一個新的內核線程的方法:
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.?????? 頭文件
#include ?? //wake_up_process()
#include //kthread_create()、kthread_run()
#include //IS_ERR()、PTR_ERR()
2.?????? 實現
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[], ...);
kthread_create源碼詳解見http://blog.sina.com.cn/s/blog_6237dcca0100gq67.html
#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;????????????????????????????????????????????????? ?? \
})
例如:
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);
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);
例如:
?????????????static?void?test_cleanup_module(void)
{
??? ????????if(test_task){
????? ????????? kthread_stop(test_task);
????? ????????? test_task = NULL;
??? ??????? }
}
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函數的第三個參數指定。?代碼:
?#include?
#include?
#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");
這個內核線程的作用就是每隔一秒打印一個“hello?world”。
值得一提的是kthread_should_stop函數,我們需要在開啟的線程中嵌入該函數并檢查此函數的返回值,否則kthread_stop是不起作用的......
總結
以上是生活随笔為你收集整理的linux驱动开发之内核线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java采集PPI指数_PPI(工业品价
- 下一篇: PPI计算公式