其他操作系统提供产生进程的机制,新的地址空间里创建进程,然后读入可执行文件,最后开始执行。
Unix采用了不同的实现方式实现进程的创建。
通过fork()和exec()两个函数
首先,fork()函数拷贝当前进程创建一个新的子进程,exec函数负责读取可执行文件,并将其载入地址空间开始运行,
fork()函数:
Linux通过clone()系统调用实现fork(),这个调用通过一系列的参数标志来指明父、子进程需要共享的资源, fork(),vfork(),__clone()库函数都根据各自需要的参数标志去调用clone(),然后clone()去调用do_fork()函数 (do_fork()函数在kernel/fork.c头文件中),该函数调用拷贝进程的函数,运行进程
copy_process()函数基本工作简单介绍如下:
为新进程创建内核栈,thread_info()和task_struct,与当前值相同,子进程和父进程描述符完全相同(关于描述符见前一章),然后进行进程的资源检查,即进程数目是否超出最大限制,接下来子进程会把自己的许多成员恢复为初始值以与父进程区别,子进程的状态被设置为TASK_UNINTERRUPTIBLE,接下来copy_process调用copy_flags()以更新task_struct的flags成员,再会调用PID分配函数为新进程获得一个有效PID, 然后根据传递给clone()的参数表标志,copy_process()拷贝,共享打开的文件,文件系统信息,信号处理函数,进程地址空间和命名空间, 最后copy_process()函数返回一个指向子进程的指针。
Linux把所有的线程都当做进程处理
创建线程:
上面讲到了利用fork()类的函数与exec()类的函数创建进程,线程创建和普通进程类似,,只是在调用clone() 的时候传递了已明确的需要共享的资源关于clone()参数标志以及他们的作用,都是在<linux/sched.h>中定义的。
内核线程:
内核经常在后台执行操作,可通过内核线程来完成,flush对缓冲的操作一般通过内核线程实现,
root 1 0 0 12:27 ? 00:00:00 /sbin/init showopts
root 2 0 0 12:27 ? 00:00:00 [kthreadd]
root 3 2 0 12:27 ? 00:00:00 [ksoftirqd/0]
root 5 2 0 12:27 ? 00:00:00 [kworker/0:0H]
root 7 2 0 12:27 ? 00:00:00 [migration/0]
root 8 2 0 12:27 ? 00:00:00 [rcuc/0]
root 9 2 0 12:27 ? 00:00:00 [rcub/0]
root 10 2 0 12:27 ? 00:00:02 [rcu_preempt]
root 11 2 0 12:27 ? 00:00:01 [rcuop/0]
root 12 2 0 12:27 ? 00:00:00 [rcuop/1]
root 13 2 0 12:27 ? 00:00:00 [rcuop/2]
root 14 2 0 12:27 ? 00:00:00 [rcuop/3]
root 15 2 0 12:27 ? 00:00:00 [rcuop/4]
root 16 2 0 12:27 ? 00:00:00 [rcuop/5]
root 17 2 0 12:27 ? 00:00:00 [rcuop/6]
root 18 2 0 12:27 ? 00:00:00 [rcuop/7]
root 19 2 0 12:27 ? 00:00:00 [rcuop/8]
root 20 2 0 12:27 ? 00:00:00 [rcuop/9]
root 21 2 0 12:27 ? 00:00:00 [rcuop/10]
root 22 2 0 12:27 ? 00:00:00 [rcuop/11]
root 23 2 0 12:27 ? 00:00:00 [rcuop/12]
root 24 2 0 12:27 ? 00:00:00 [rcuop/13]
查看linux内核线程,部分截图
在<linux/kthread.h>可看到关于内核线程创建有关内容,当然,内核线程也只有内核线程创建。
struct task_struct *kthread_create(int (*threadfn)(void *data),...)
struct task_struct *kthread_run
#define kthread_run(threadfn, data, namefmt...) \ ({ \ struct task_struct *k; \ k=kthread_create(threadfn,data,namefmt,## __VA_ARGS__ ); \ if(!IS_ERR(k)) \ wake_up_process(k); \ k; \ }) \