本文共 4190 字,大约阅读时间需要 13 分钟。
在需要多任务的编程中,多数情况下都是使用的pthread,网上查找资料的话,也有很多使用fork/vfork的例子。
pthread是线程,fork是进程,这是没有疑问的。
但是有资料又说,linux不区分进程和线程,或者说根本就没有实现线程。
可但是又有资料明明写着,有linux有内核线程。。。,查看内核代码确有kernel_thread,
真是傻傻分不清楚。
那么,下面就试着理一理头绪,不一定正确,只代表了当前的认识。
1.kernel_thread
内核源码:
init/main.c
asmlinkage void __init start_kernel(void)-->
static noinline void __init_refok rest_init(void){
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
cpu_idle();
}
rest_init中启动了两个内核线程kernel_init和kthreadd,
rest_init本身也是一个内核线程,最后死在cpu_idle中。
此后还会有很多地方
(待续。。。。。。)
在内核启动过程中会有很多地方通过kernel_thread创建内核线程(只是创建方法不像kernel_init和kthreadd这样显示调用)
大部分启动完成,干完自己的活就退出了。
这里rest_init本身是线程0, pid为0; kernel_init的pid为1,kthreadd的pid为2.
kernel_init最后会调用/sbin/init程序,成为第一个用户进程。
(待续。。。。。)
看一下kernel_thread的源码
/*
* Create a kernel thread.
*/
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;
memset(®s, 0, sizeof(regs));
regs.ARM_r4 = (unsigned long)arg;
regs.ARM_r5 = (unsigned long)fn;
regs.ARM_r6 = (unsigned long)kernel_thread_exit;
regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
regs.ARM_pc = (unsigned long)kernel_thread_helper;
regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);
也就是kernel_thread是通过do_fork实现的,当用户程序通过fork创建进程的时候,内核同样会进入到do_fork.
因此这就证明了,linux内核不区分线程和进程,他们是同一个东西,内核线程,也可以叫内核进程。
(待续。。。。)
kernel_init和kthreadd可以说是纯手工打造的,在内核启动的时候会创建很多内核线程,我们在写一个设备驱动的时候也可能需要创建一个线程
而这些地发不能用这种手工的方式,而是有更加通用的API。我们看一下kthreadd都做了什么
int kthreadd(void *unused){ struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); printk("[%s-%d][%s] current->pid=%d,current->tgid=%d current->state=%d current->comm=%s\n",__FILE__,__LINE__,__func__,current->pid,current->tgid,current->state,current->comm); 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; printk("[%s-%d][%s] current->pid=%d,current->tgid=%d current->state=%d\n",__FILE__,__LINE__,__func__,current->pid,current->tgid,current->state); for (;;) { printk("[%s-%d][%s] current->pid=%d,current->tgid=%d current->state=%d\n",__FILE__,__LINE__,__func__,current->pid,current->tgid,current->state); set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)){ printk("[%s-%d][%s] call schedule\n",__FILE__,__LINE__,__func__); schedule(); } __set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock); while (!list_empty(&kthread_create_list)) { //检查list是否为空 struct kthread_create_info *create; create = list_entry(kthread_create_list.next, //获取一个create请求 struct kthread_create_info, list); list_del_init(&create->list); spin_unlock(&kthread_create_lock); printk("[%s-%d][%s] create->threadfn=0x%x\n",__FILE__,__LINE__,__func__,create->threadfn); create_kthread(create); //创建内核线程 spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0;}
可以看到kthreadd就是查看kthread_create_list 如果不为空,则从列表取出一个create(请求),然后执行create_kthread(create);
去创建一个内核线程,可以想到一定有一个地发将这个create请求放到kthread_create_list上,它就是一个通用的创建内核线程的API,如下
struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...){ struct kthread_create_info create; create.threadfn = threadfn; create.data = data; init_completion(&create.done); spin_lock(&kthread_create_lock); list_add_tail(&create.list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); wait_for_completion(&create.done); if (!IS_ERR(create.result)) { struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); vsnprintf(create.result->comm, sizeof(create.result->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); set_cpus_allowed_ptr(create.result, cpu_all_mask); } return create.result;}EXPORT_SYMBOL(kthread_create);
转载地址:http://prqji.baihongyu.com/