任督二脉之进程管理

Posted shihuvini

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了任督二脉之进程管理相关的知识,希望对你有一定的参考价值。

一、第二次课大纲
1.fork、vfork、clone
2.写时拷贝技术
3.Linux线程的实现本质
4.进程0和进程1
5.进程的睡眠和等待队列
6.孤儿进程的托孤,SUBREAPER
1.fork、vfork、Copy-on-Write例子
2.life-period例子,实验体会托孤
3.pthread_create例子,strace它
4.彻底看懂等待队列的案例

二、fork

1)fork创建一个进程。p1是一个task_struct,p2也是一个task_struct,调度器只通过task_struct来调度进程。在p1中fork后新进程p2,直接完全对拷给p2的task_struct,两者完全一样(当然pid不同),资源一样。只要有修改就不一样了,资源分裂。比如fs,fd等。chdir函数修改cwd。

技术分享图片

2)但是内存资源mm不好分裂。采用写时拷贝技术(COW)

例子:

技术分享图片
 1 #include <sched.h>
 2 
 3 #include <unistd.h>
 4 
 5 #include <stdio.h>
 6 
 7 #include <stdlib.h>
 8 
 9 
10 
11 int data = 10;
12 
13 
14 
15 int child_process()
16 
17 {
18 
19     printf("Child process %d, data %d
",getpid(),data);
20 
21     data = 20;
22 
23     printf("Child process %d, data %d
",getpid(),data);
24 
25     _exit(0);
26 
27 }
28 
29 
30 
31 int main(int argc, char* argv[])
32 
33 {
34 
35     int pid;
36 
37     pid = fork();
38 
39 
40 
41     if(pid==0) {
42 
43         child_process();
44 
45     }
46 
47     else{
48 
49         sleep(1);
50 
51         printf("Parent process %d, data %d
",getpid(), data);
52 
53         exit(0);
54 
55     }
56 
57 }
View Code

运行结果:

技术分享图片

 

下面是COW详细过程:fork后父子进程的页表完全一样,但是只有RD_ONLY,其中一个进程P2修改数据,那么就申请一个新的物理页面,把原页面数据拷贝到新的物理页面,再修改P2进程页表。

技术分享图片

 

3)从上面可以看出,COW技术依赖于MMU(硬件),那么没有MMU的系统,比如uclinux,不能执行COW,没有fork函数,只有vfork。vfork会阻塞父进程(子进程调用_exit,exec之一才返回)。所以vfork后P1和P2的mm指针指向同一个地址。

 

技术分享图片

vfork后P1和P2的mm指针指向同一个地址。

技术分享图片

 

例子:

技术分享图片
 1 #include <sched.h>
 2 
 3 #include <unistd.h>
 4 
 5 #include <stdio.h>
 6 
 7 #include <stdlib.h>
 8 
 9 
10 
11 int data = 10;
12 
13 
14 
15 int child_process()
16 
17 {
18 
19     printf("Child process %d, data %d
",getpid(),data);
20 
21     data = 20;
22 
23     printf("Child process %d, data %d
",getpid(),data);
24 
25     _exit(0);
26 
27 }
28 
29 
30 
31 int main(int argc, char* argv[])
32 
33 {
34 
35     int pid;
36 
37     pid = vfork();
38 
39 
40 
41     if(pid==0) {
42 
43         child_process();
44 
45     }
46 
47     else{
48 
49         sleep(1);
50 
51         printf("Parent process %d, data %d
",getpid(), data);
52 
53         exit(0);
54 
55     }
56 
57 }
View Code

 运行结果:

技术分享图片

 

那么可以放大,把各种资源全部指向同一个地址,资源全部共享。也即pthread_create(其调用了clone函数,再共享其他资源),这就是轻量级进程,即线程。

技术分享图片

4)也可以只共享部分资源,clone函数的参数指定。既不是进程也不是线程。

 技术分享图片

5)PID和TGID

以上fork,vfork,clone都会产生新的task_struct,有独立的pid。POSIX要求一个进程里面有多个线程,必须对外表现为一个整体,getpid时是同一个值。linux就增加一个TGID=P1。

技术分享图片

例子:

技术分享图片
 1 #include <stdio.h>
 2 #include <pthread.h>
 3 #include <stdio.h>
 4 #include <linux/unistd.h>
 5 #include <sys/syscall.h>
 6 
 7 static pid_t gettid( void )
 8 {
 9 
10     return syscall(__NR_gettid);
11 
12 }
13 
14 static void *thread_fun(void *param)
15 {
16 
17     printf("thread pid:%d, tid:%d pthread_self:%lu
", getpid(), gettid(),pthread_self());
18 
19     while(1);
20 
21     return NULL;
22 }
23 
24 int main(void)
25 {
26     pthread_t tid1, tid2;
27     int ret;
28 
29     printf("thread pid:%d, tid:%d pthread_self:%lu
", getpid(), gettid(),pthread_self());
30     /*getpid():TGID, gettid():内核空间的pid,pthread_self(): 用户空间thread库里的id*/
31 
32 
33     ret = pthread_create(&tid1, NULL, thread_fun, NULL);
34 
35     if (ret == -1) {
36 
37         perror("cannot create new thread");
38 
39         return -1;
40 
41     }
42 
43     ret = pthread_create(&tid2, NULL, thread_fun, NULL);
44     if (ret == -1) {
45         perror("cannot create new thread");
46         return -1;
47     }
48 
49     if (pthread_join(tid1, NULL) != 0) {
50         perror("call pthread_join function fail");
51         return -1;
52     }
53 
54     if (pthread_join(tid2, NULL) != 0) {
55         perror("call pthread_join function fail");
56         return -1;
57     }
58 
59     return 0;
60 }
View Code

top命令看到的多线程进程是一个整体,top -H就是线程视角,也可以运行top后按H转换视角。

pstree:

技术分享图片

进程视角:

技术分享图片

线程视角:

技术分享图片

 

 三、subreaper和托孤

subreaper:通过系统调用设置自己为subreaper,pstree里面显示为init的为subreaper。

技术分享图片

在进程退出后会在父子关系树向上找sbureaper,把子进程托孤给它,找不到sbureaper看托孤给init进程。

技术分享图片

 

例子,托孤:先pstree观察父子进程在树形结构中的位置,然后把父进程杀掉,pstree观察子进程在树形结构中的位置变化。

技术分享图片
 1 #include <stdio.h>
 2 #include <sys/wait.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 
 6 int main(void)
 7 {
 8     pid_t pid,wait_pid;
 9     int status;
10 
11     pid = fork();
12     if (pid==-1) {
13         perror("Cannot create new process");
14         exit(1);
15     } else     if (pid==0) {
16         printf("child process id: %ld
", (long) getpid());
17         pause();
18         _exit(0);
19     } else {
20         printf("parent process id: %ld
", (long) getpid());
21         wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED);
22         if (wait_pid == -1) {
23 
24             perror("cannot using waitpid function");
25             exit(1);
26 
27         }
28         
29         if(WIFSIGNALED(status))
30             printf("child process is killed by signal %d
", WTERMSIG(status));
31             
32         exit(0);
33     }
34 }
View Code

 三、睡眠:深度睡眠VS浅度睡眠

技术分享图片

睡眠的实现:关键--等待队列(类似设计模式中的观察者模式),等待资源的进程加入等待队列,资源到来后唤醒等待队列不会唤醒单个进程。看globalfifo代码:https://github.com/21cnbao/process-courses/blob/master/day2/globalfifo.c

技术分享图片

 

 四、进程0和1

 1号进程的父进程pid=0。但是pstree里面看不到0号进程,实际上0号进程创建完init进程后就退化为idle进程,也就是其他进程都不用cpu的情况下才运行,也即调度优先级最低,进入睡眠状态WFI,省电。设计的好处:每个进入进入睡眠之前就查一下是不是最后一个进程,是的话就置为WFI低功耗,这样就耦合到了每个进程里面;idle的设计就没有耦合了。

 1 [email protected]:~/vmware-tools-distrib$ cat /proc/1/status
 2 Name:    systemd
 3 State:    S (sleeping)
 4 Tgid:    1
 5 Ngid:    0
 6 Pid:    1
 7 PPid:    0
 8 TracerPid:    0
 9 Uid:    0    0    0    0
10 Gid:    0    0    0    0
11 FDSize:    256
12 Groups:    
13 NStgid:    1
14 NSpid:    1
15 NSpgid:    1
16 NSsid:    1

 五、问答

1、进程0是天上掉下来的,是从boot跑到linux。???????也是有task_struct的。

2、vfork阻塞父进程,子进程一般是创建后执行exec。
3、多线程的进程,/proc/tgid/task/pid。

4、MMU原理,数据结构

http://ytliu.info/blog/2014/11/24/shi-shang-zui-xiang-xi-de-kvm-mmu-pagejie-gou-he-yong-fa-jie-xi/

 












以上是关于任督二脉之进程管理的主要内容,如果未能解决你的问题,请参考以下文章

Linux阅码场原创精华文章汇总

“智慧”交通打通城市的任督二脉

K2 BPM_当K2遇上医药,用流程打通企业的任督二脉_业务流程管理系统

案例干货|用友罗涛:打通产品开发的任督二脉

10段代码打通js学习的任督二脉

开篇词 | 打通“容器技术”的任督二脉