linux内核多线程Word文档格式.docx
- 文档编号:17962022
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:14
- 大小:22.15KB
linux内核多线程Word文档格式.docx
《linux内核多线程Word文档格式.docx》由会员分享,可在线阅读,更多相关《linux内核多线程Word文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
printf-stylenameforthethread.**Description:
Convenientwrapperforkthread_create()followedby*wake_up_process().ReturnsthekthreadorERR_PTR(-ENOMEM).*/#definekthread_run(threadfn,data,namefmt,...)\
({
structtask_struct*__k
=kthread_create(threadfn,data,namefmt,##__VA_ARGS__);
if(!
IS_ERR(__k))
wake_up_process(__k);
__k;
})
kthread_run()负责内核线程的创建,它由kthread_create()和wake_up_process()两部分组成,这样的
好处是用kthread_run()创建的线程可以直接运行。
外界调用kthread_run创建运行线程。
kthread_run是个宏定义,首先调用
kthread_create()创建线程,如果创建成功,再调用wake_up_process()唤醒新创建的线程。
kthread_create()根据参数向kthread_create_list中发送一个请求,并唤醒kthreadd,之后会调用
wait_for_completion(&
amp;
create.done)等待线程创建完成。
新创建的线程开始运行后,入口在
kthread(),kthread()调用complete(&
create-&
gt;
done)唤醒阻塞的模块进程,并使用
schedule()调度出去。
kthread_create()被唤醒后,设置新线程的名称,并返回到kthread_run中。
kthread_run调用wake_up_process()重新唤醒新创建线程,此时新线程才开始运行kthread_run参数中的入口函数。
在介绍完如何创建线程之后,下面来介绍另外两个基本的函数:
intkthread_stop(structtask_struct*k);
intkthread_should_stop(void);
kthread_stop()负责结束创建的线程,参数是创建时返回的task_struct指针。
kthread设置标志
should_stop,并等待线程主动结束,返回线程的返回值。
在调用kthread_stop()结束线程之前一定要检查该线程是否还在运行(通过
kthread_run返回的task_stuct
是否有效),否则会造成灾难性的后果。
kthread_run的返回值tsk。
不能用tsk是否为NULL进行检查,而要用IS_ERR()宏定义检查,
这是因为返回的是错误码,大致从0xfffff000~0xffffffff。
kthread_should_stop()返回should_stop标志(参见structkthread)。
它用于创建的线程检查结束标志,并决定是否退出。
kthread()(注:
原型为:
staticintkthread(void
*_create))的实现在kernel/kthread.c中,头文件是include/linux/kthread.h。
内核中一直运行一个线程
kthreadd,它运行kthread.c中的kthreadd函数。
在kthreadd()中,不断检查一个kthread_create_list
链表。
kthread_create_list中的每个节点都是一个创建内核线程的请求,kthreadd()发现链表不为空,就将其第一个节点退出链
表,并调用create_kthread()创建相应的线程。
create_kthread()则进一步调用更深层的kernel_thread()创建
线程,入口函数设在kthread()中。
外界调用kthread_stop()删除线程。
kthread_stop首先设置结束标志should_stop,然后调用
wake_for_completion(&
kthread-&
exited)上,这个其实是新线程task_struct上的
vfork_done,会在线程结束调用do_exit()时设置。
附:
structkthread{intshould_stop;
structcompletionexited;
};
intkthreadd(void*unused)
{structtask_struct*tsk=current;
/*Setupacleancontextforourchildrentoinherit.*/set_task_comm(tsk,"
kthreadd"
);
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk,cpu_all_mask);
set_mems_allowed(node_states[N_HIGH_MEMORY]);
current-&
flags|=PF_NOFREEZE|PF_FREEZER_NOSIG;
for(;
;
){set_current_state(TASK_INTERRUPTIBLE);
if(list_empty(&
kthread_create_list))schedule();
__set_current_state(TASK_RUNNING);
spin_lock(&
kthread_create_lock);
while(!
list_empty(&
kthread_create_list)){structkthread_create_info*create;
create=list_entry(kthread_create_list.next,structkthread_create_info,list);
list_del_init(&
list);
spin_unlock(&
create_kthread(create);
}spin_unlock(&
}return0;
}/***kthread_stop-stopathreadcreatedbykthread_create().*@k:
threadcreatedbykthread_create().**Setskthread_should_stop()for@ktoreturntrue,wakesit,and*waitsforittoexit.Thiscanalsobecalledafterkthread_create()*insteadofcallingwake_up_process():
thethreadwillexitwithout*callingthreadfn().**Ifthreadfn()maycalldo_exit()itself,thecallermustensure*task_structcan'
tgoaway.**Returnstheresultofthreadfn(),or%-EINTRifwake_up_process()*wasnevercalled.*/intkthread_stop(structtask_struct*k)
{structkthread*kthread;
intret;
trace_sched_kthread_stop(k);
get_task_struct(k);
kthread=to_kthread(k);
barrier();
/*itmighthaveexited*/if(k-&
vfork_done!
=NULL){kthread-&
should_stop=1;
wake_up_process(k);
wait_for_completion(&
exited);
}ret=k-&
exit_code;
put_task_struct(k);
trace_sched_kthread_stop_ret(ret);
returnret;
}Linux内核多线程
(二)
内核多线程是在项目中使用到,自己也不熟悉,遇到一个很囧的问题,导致cpu运行100%。
这是写的第一个内核线程程序,通过全局变量来实现两个内核线程之间的通信。
但是这里遇到致命错误,就是:
每当
wait_event_interruptible()被wake_up_interruptible
唤醒之后线程就进入死循环。
后面发现是线程不会主动的自己调度,需要显式的通过schedule或者
schedule_timeout()来调度。
如果不加tc=0
这一行,wait_event_intrruptible()就一直不会睡眠(参见前面的文章“等待队列”),不会被调度放弃CPU,因此进入死循环。
这个过程可以通过分析wait_event_intrruptible()的源代码来看出。
#include&
lt;
linux/init.h&
#include&
linux/module.h&
linux/kthread.h&
linux/wait.h&
MODULE_LICENSE("
DualBSD/GPL"
staticstructtask_struct*_tsk;
staticstructtask_struct*_tsk1;
staticinttc=0;
staticwait_queue_head_tlog_wait_queue;
staticintthread_function(void*data)
{do{ printk(KERN_INFO"
INthread_functionthread_function:
%dtimes\n"
tc);
wait_event_interruptible(log_wait_queue,tc==10);
tc=0;
///必须加这一行,内核才会进行调度。
内核线程不像应用程序会主动调度,我们需要显式的使用调度函数,
想要在thread_function_1中去重置tc的值是不可能的,因为线程不会被调度,该线程会一直占用CPU
printk(KERN_INFO"
hasbeenwokeup!
\n"
}while(!
kthread_should_stop());
returntc;
}staticintthread_function_1(void*data)
{do{ printk(KERN_INFO"
INthread_function_1thread_function:
%dtimes\n"
++tc);
if(tc==10&
&
waitqueue_active(&
log_wait_queue)){wake_up_interruptible(&
log_wait_queue);
}msleep_interruptible(1000);
}
staticinthello_init(void){printk(KERN_INFO"
Hello,world!
init_waitqueue_head(&
_tsk=kthread_run(thread_function,NULL,"
mythread"
if(IS_ERR(_tsk)){//需要使用IS_ERR()来判断线程是否有效,后面会有文章介绍IS_ERR()printk(KERN_INFO"
firstcreatekthreadfailed!
}else{printk(KERN_INFO"
firstcreatektrheadok!
}_tsk1=kthread_run(thread_function_1,NULL,"
mythread2"
if(IS_ERR(_tsk1)){printk(KERN_INFO"
secondcreatekthreadfailed!
secondcreatektrheadok!
staticvoidhello_exit(void)
{printk(KERN_INFO"
Hello,exit!
IS_ERR(_tsk)){intret=kthread_stop(_tsk);
Firstthreadfunctionhasstopped,return%d\n"
ret);
}if(!
IS_ERR(_tsk1)){intret=kthread_stop(_tsk1);
Secondthreadfunction_1hasstopped,return%d\n"
ret);
}}
module_init(hello_init);
module_exit(hello_exit);
说明:
这个程序的目的就是,使用一个线程(thread_function_1)通知另外一个线程(thread_function)某个条件(tc==10)满足(比如接收线程收到10帧然后通知处理线程处理接收到的数据)
运行结果:
程序加载并运行(tc的值等于10之后就会唤醒另外一个线程,之后tc又从10开始计数):
程序卸载(程序卸载其实还是要很注意的,很多程序在卸载的时候回出现各种问题后面文章会提到):
这里介绍另一种线程间通信的方式:
completion机制。
Completion机制是线程间通信的一种轻量级机制:
允许一个线程告诉另一个线程工作已经完成。
为使用completion,需要包含头文件&
linux/completion.h&
。
可以通过以下方式来创建一个completion:
DECLARE_COMPLETION(my_completion);
或者,动态创建和初始化:
structcompletionmy_completion;
init_completion(&
my_completion);
等待completion是一个简单事来调用:
voidwait_for_completion(structcompletion*c);
注意:
这个函数进行一个不可打断的等待.如果你的代码调用wait_for_completion并且
没有人完成这个任务,结果会是一个不可杀死的进程。
completion事件可能通过调用下列之一来发出:
voidcomplete(structcompletion*c);
voidcomplete_all(structcompletion*c);
如果多于一个线程在等待同一个completion事件,这2个函数做法不同.complete只
唤醒一个等待的线程,而complete_all允许它们所有都继续。
下面来看使用completion机制的实现代码:
staticstructcompletioncomp;
staticstructtask_struct*_tsk;
{do{ printk(KERN_INFO"
comp);
//tc=0;
///在哪里都行
}staticintthread_function_1(void*data)
{do{ printk(KERN_INFO"
if(tc==10)
{complete(&
}staticinthello_init(void)
init_completion(&
if(IS_ERR(_tsk)){printk(KERN_INFO"
}staticvoidhello_exit(void)
}}module_init(hello_init);
自己创建的内核线程,当把模块加载到内核之后,可以通过:
ps–ef
命令来查看线程运行的情况。
通过该命令可以看到该线程的pid和ppid等。
也可以通过使用kill–s9pid
来杀死对应pid的线程。
如果要支持kill命令自己创建的线程里面需要能接受kill信号。
这里我们就来举一个例,支持kill命令,同时rmmod的
时候也能杀死线程。
linux/kernel.h&
linux/param.h&
linux/jiffies.h&
asm/system.h&
asm/processor.h&
asm/signal.h&
//forDECLARE_COMPLETION()#include&
linux/sched.h&
linux
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 多线程