在linux内核中,所谓的内核线程实际上是一个共享父进程地址空间的进程,它有自己的系统堆栈;所以它们依然是一个进程,只不过这些进程可以与其他进程共享某些资源,这里的其他进程也是所谓的线程。
1 内核线程与普通进程的异同
1.1 内核线程没有自己的地址空间,所以它们的"current->mm"都是空的;
1.2 内核线程只能在内核空间操作,不能与用户空间交互;
1.3 跟普通进程一样,内核线程也有优先级和被调度。
2 内核线程创建
在内核中,有两种方法可以生成内核线程,一种是使用kernel_thread()接口,另一种是用kthread_create()接口。
先说kernel_thread接口,使用该接口创建的线程,必须在该线程中调用daemonize()函数,这是因为只有当线程的父进程指向"Kthreadd"时,该线程才算是内核线程,而恰好daemonize()函数主要工作便是将该线程的父进程改成“kthreadd"内核线程;默认情况下,调用deamonize()后,会阻塞所有信号,如果想操作某个信号可以调用allow_signal()函数。
而kthread_create接口,则是标准的内核线程创建接口,只须调用该接口便可创建内核线程;默认创建的线程是存于不可运行的状态,所以需要在父进程中通过调用wake_up_process()函数来启动该线程。
3 内核线程的退出
当线程执行到函数末尾时会自动调用内核中do_exit()函数来退出或其他线程调用kthread_stop()来指定线程退出。
4 内核线程接口
4.1 kernel_thread接口
-
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
// fn为线程函数,arg为线程函数参数,flags为标记
-
void daemonize(const char * name,...); // name为内核线程的名称
注:这里的flags的取值为
-
CSIGNAL /* signal mask to be sent at exit */
-
CLONE_VM /* set if VM shared between processes */
-
CLONE_FS /* set if fs info shared between processes */
-
CLONE_FILES /* set if open files shared between processes */
-
CLONE_SIGHAND /* set if signal handlers and blocked signals shared */
-
CLONE_PTRACE /* set if we want to let tracing continue on the child too */
-
CLONE_VFORK /* set if the parent wants the child to wake it up on mm_release */
-
CLONE_PARENT /* set if we want to have the same parent as the cloner */
-
CLONE_THREAD /* Same thread group? */
-
CLONE_NEWNS /* New namespace group? */
-
CLONE_SYSVSEM /* share system V SEM_UNDO semantics */
-
CLONE_SETTLS /* create a new TLS for the child */
-
CLONE_PARENT_SETTID /* set the TID in the parent */
-
CLONE_CHILD_CLEARTID /* clear the TID in the child */
-
CLONE_DETACHED /* Unused, ignored */
-
CLONE_UNTRACED /* set if the tracing process can't force CLONE_PTRACE
-
on this clone */
-
CLONE_CHILD_SETTID /* set the TID in the child */
-
CLONE_NEWUTS /* New utsname group? */
-
CLONE_NEWIPC /* New ipcs */
-
CLONE_NEWUSER /* New user namespace */
-
CLONE_NEWPID /* New pid namespace */
-
CLONE_NEWNET /* New network namespace */
-
CLONE_IO /* Clone io context */
4.2 kthread_create接口
-
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,
-
const char namefmt[], ...);
-
//threadfn为线程函数;data为线程函数参数;namefmt为线程名称,可被格式化的
-
int wake_up_process(struct task_struct *p); //唤醒线程
-
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,
-
const char namefmt[], ...);//是以上两个函数的功能的总和
注:因为线程也是进程,所以其结构体也是使用进程的结构体"struct task_struct"。
5 示例代码 kthread.rar
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/kernel.h>
-
#include <linux/kthread.h>
-
-
MODULE_LICENSE("Dual BSD/GPL");
-
MODULE_AUTHOR("Kozo");
-
-
static int noop(void *dummy)
-
{
-
int i = 0;
-
daemonize("mythread"); /*使用kernel_thread创建的线程,需要调用该函数*/
-
while(i++ < 5)
-
{
-
printk("my thread:current->mm = %p\n",current->mm);
-
printk("my thread:current->active_mm = %p\n",current->active_mm);
-
set_current_state(TASK_INTERRUPTIBLE);
-
schedule_timeout(10*HZ);
-
}
-
return 0;
-
}
-
-
static int noop2(void *dummy)
-
{
-
int i = 0;
-
while(i++ < 5)
-
{
-
printk("my thread:current->mm = %p\n",current->mm);
-
printk("my thread:current->active_mm = %p\n",current->active_mm);
-
set_current_state(TASK_INTERRUPTIBLE);
-
schedule_timeout(10*HZ);
-
}
-
return 0;
-
}
-
static __init int demo_init(void)
-
{
-
-
printk(KERN_INFO"demo init\n");
-
printk("demo init:current->mm = %p\n",current->mm);
-
printk("demo init:current->active_mm = %p\n",current->active_mm);
-
//kernel_thread(noop, NULL, CLONE_KERNEL|SIGCHLD);
-
kthread_run(noop2,NULL,"mythread");
-
return 0;
-
}
-
-
static __exit void demo_exit(void)
-
{
-
printk(KERN_INFO"demo exit\n");
-
}
-
-
module_init(demo_init);
-
module_exit(demo_exit);
6 执行结果
从结果可以看出,子线程的地址空间是没有的。
转载请注明出处:
add358.blog.chinaunix.net
阅读(227) | 评论(0) | 转发(0) |