基于內(nèi)核線程的創(chuàng)建、使用和退出以及延時(shí)宏的補(bǔ)充說明介紹
相關(guān)函數(shù):
kthread_create():創(chuàng)建內(nèi)核線程
struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...); kernel thread可以用kernel_thread創(chuàng)建,但是在執(zhí)行函數(shù)里面必須用daemonize釋放資源并掛到init下,還需要用completion等待這一過程的完成。為了簡(jiǎn)化操作,定義了kthread_create。
線程創(chuàng)建后,不會(huì)馬上運(yùn)行,而是需要將kthread_create() 返回的task_struct指針傳給wake_up_process(),然后通過此函數(shù)運(yùn)行線程。
kthread_run():創(chuàng)建并啟動(dòng)線程的函數(shù)。
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);它實(shí)際上是個(gè)宏,由kthread_create()和wake_up_process()組成。
它實(shí)際上是個(gè)宏,由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():通過發(fā)送信號(hào)給線程,使之退出。
int kthread_stop(struct task_struct *thread);
線程一旦啟動(dòng)起來后,會(huì)一直運(yùn)行,除非該線程主動(dòng)調(diào)用do_exit函數(shù),或者其他的進(jìn)程調(diào)用kthread_stop函數(shù),結(jié)束線程的運(yùn)行。
但如果線程函數(shù)正在處理一個(gè)非常重要的任務(wù),它不會(huì)被中斷的。當(dāng)然如果線程函數(shù)永遠(yuǎn)不返回并且不檢查信號(hào),它將永遠(yuǎn)都不會(huì)停止。
同時(shí),在調(diào)用kthread_stop函數(shù)時(shí),線程函數(shù)不能已經(jīng)運(yùn)行結(jié)束。否則,kthread_stop函數(shù)會(huì)一直進(jìn)行等待。
內(nèi)核線程的一般框架
int threadfunc(void *data){
…
while(1){
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop()) break;
if(){//條件為真
//進(jìn)行業(yè)務(wù)處理
}
else{//條件為假
//讓出CPU運(yùn)行其他線程,并在指定的時(shí)間內(nèi)重新被調(diào)度
schedule_timeout(HZ);
}
}
…
return 0;
}
線程相關(guān)測(cè)試命令
可以使用top命令來查看線程(包括內(nèi)核線程)的CPU利用率。命令如下:
top –p 線程號(hào)
可以使用下面命令來查找線程號(hào):
ps aux|grep 線程名
示例程序:使用模塊加載內(nèi)核線程,實(shí)現(xiàn)每1s在內(nèi)核中打印字符。
(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;#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;
}
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");
補(bǔ)充說明:
這個(gè)延時(shí)宏在一些情況下會(huì)造成內(nèi)核線程CPU占用率過高的情況。根據(jù)對(duì)schedule_timeout()源碼的分析,它只是周期使線程成為TASK_RUNNING狀態(tài),這個(gè)線程并沒有真正的睡眠。解決辦法:在while循環(huán)中的起始處加入set_current_state(TASK_INTERRUPTIBLE)即可。
相關(guān)文章
C語言實(shí)現(xiàn)經(jīng)典小游戲井字棋的示例代碼
這個(gè)三子棋游戲是在學(xué)習(xí)C語言的過程中自己編寫的一個(gè)小游戲,現(xiàn)在將自己的思路(主要以流程圖形式和代碼中的注釋表達(dá))和具體代碼以及運(yùn)行結(jié)果分享出來以供大家學(xué)習(xí)參考,希望對(duì)大家有所幫助2022-11-11C/C++中的sizeof運(yùn)算符和size_t類型的詳解
今天小編就為大家分享一篇關(guān)于C/C++中的sizeof運(yùn)算符和size_t類型的詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10Qt利用QSortFilterProxyModel代理實(shí)現(xiàn)自定義排序與聯(lián)合過濾
QsortFilterProxyModel類用來為model和view之間提供強(qiáng)大的排序和過濾支持。這篇文章將利用QSortFilterProxyModel代理實(shí)現(xiàn)自定義排序與聯(lián)合過濾,需要的可以參考一下2022-11-11c++如何控制對(duì)象的創(chuàng)建方式(禁止創(chuàng)建棧對(duì)象or堆對(duì)象)和創(chuàng)建的數(shù)量
這篇文章主要介紹了c++如何控制對(duì)象的創(chuàng)建方式和創(chuàng)建的數(shù)量,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08C++中string與int的相互轉(zhuǎn)換實(shí)現(xiàn)代碼
這篇文章主要介紹了C++中string與int的相互轉(zhuǎn)換實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-05-05C++實(shí)現(xiàn)基數(shù)排序的方法詳解
本篇文章是對(duì)使用C++實(shí)現(xiàn)基數(shù)排序的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Qt學(xué)習(xí)之QListWidget控件的使用教程詳解
這篇文章主要為大家詳細(xì)介紹了Qt中QListWidget控件的使用教程,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Qt有一定的幫助,需要的可以參考一下2022-12-12Visual?Studio2022配置ReSharper?C++?常用設(shè)置方法
這篇文章主要介紹了Visual?Studio2022配置ReSharper?C++?常用設(shè)置,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),文中介紹了卸載Resharper的方法及Resharper激活碼,感興趣的朋友參考下吧2024-01-01