linux上进程的一些问题

main进程终止:

                图片来自linux环境高级编程150页

 1 #include<cstdlib>                                                                    
 2 #include<cstdio>                                                                     
 3                                                                                      
 4 static void my_exit1(void)                                                           
 5 {                                                                                    
 6   printf("first exit handler\n");                                                    
 7 }                                                                                    
 8 static void my_exit2(void)                                                           
 9 {                                                                                    
10   printf("second exit handler\n");                                                   
11 }                                                                                    
12                                                                                      
13 int main()                                                                           
14 {                                                                                    
15   if(atexit(my_exit1) != 0)   //#include<cstdlib>先注册的终止处理程序后被调用,FILO                                               
16     printf("error_exit1\n");                                                         
17   if(atexit(my_exit2) != 0)                                                          
18     printf("error_exit2\n");                                                         
19   printf("main is done\n");                                                          
20   exit(0); // == return 0; 0表示终止状态码,正常终止 #include<cstdlib>                                         
21 }

  

 上面代码片段使用不同的链接方式:

  

 获取环境变量(以前的main含有第三个参数:环境变量。最后虽然取消了第三个参数,但是环境变量还是会在程序执行之前传入)

1   const char* env ;                                                                  
2   env = getenv("PATH");  //#include<cstdlib>                                                    
3   printf("PATH = %s",env);  

 fork()系统调用:

  先来张图片:这不就是shell的核心程序吗!在操作系统完成启动后(中间过程登录等略去)会弹出一个shell,shell的主体结构如下,从命令行获取cmd,然后fork()一个进程就行执行,原本的shell程序执行体阻塞

    

 

   这里面有三个问题,①为什么是!fork()?②为什么使用exec()或者说exec()干嘛了?③wait()做什么事情。

  ①fork()是一个系统调用,那么必然触发int0x80中断进入内核态,进入内核态后,fork创建一个子进程(创建进程无非就是分配资源),fork主要创建子进程的pcb以及栈,因为fork创建的子进程和父进程共享代码段,数据段等等,只有子进程进行写入时才会触发写时拷贝机制进行内存的重新分配,写入为子进程分配的内存空间中。有意思的地方到了,fork()完成子进程的创建后,现在已经不仅仅只有父进程一个执行序列了,而是两个执行序列,还有一个是子进程的执行序列,上图if()语句被两个执行序列都执行了(因为子进程共享父进程的代码段),但是区别来了,父进程调用fork返回后的返回值是不等于0的,因此,if条件不会满足,就会跳过if后面的语句去执行wait(),而新创建的子进程执行序列,执行到if语句时,if条件成立,因此会执行exec系统调用。

  ②exec()是个系统调用,因此也要通过int0x80中断进入内核态,调用sys_exec,它的主要作用就是,将cmd程序的入口代码的cs,ip放到内核栈中,当从内核返回时,会进行内核栈的弹栈,就返回到了cmd程序的执行入口。因此exec系统调用成功使fork()出来的子进程去执行一个可执行程序(这不就是shell中输入的那么指令么,例如ls,exec将ls的执行代码的入口地址写入了子进程对应的内核栈中,弹栈时会到ls入口处执行)。

  ③wait():父进程调用wait()后处于一个阻塞状态,父进程开始阻塞,cpu便执行进程调度,子进程成功的被调度后执行。这样就很完美。当然wait还有另个一个作用,不仅仅是阻塞,它阻塞到这里会等待子进程结束,子进程结束后,父进程通过wait()会获得子进程的状态,释放子进程剩余的资源。如果不使用wait,也就是说子进程结束后,父进程不去获取子进程的结束状态,那么该子进程就会成为了僵尸进程。

  ④上诉三个过程加上最上面的main程序启动终止图就更容易理解了。这里的重点便是fork()后实际产生了两个指令序列,以及exec将子进程重父进程共享过来的指令序列进行修改成exec的过程,wait做后续子进程的处理。

类unix系统的登录

  本地登录:系统完成启动后,会产生一个init进程(用户态pid为1的进程,所有进程都是由init直接或间接派生出来的)。init进程读取/etc/ttys,为每一个终端设备调用一次fork,生成的子进程调用exec函数执行getty程序,getty调用open函数打开终端,终端被打开则文件描述符被0、1、2被创建与终端绑定,终端便可读可写。然后子进程继续调用exec将login代码载入执行,屏幕便有了login:。用户即可以登录了。

  

      图片来自unix环境高级编程214页

  网络登录:如果服务器上运行一个telnet远程服务程序,当客户端有远程连接请求到达时,telnet打开一个伪终端(pseudo terminal)并fork一个子进程,将文件描述符0、1、2与伪终端绑定,执行一个exec函数加载login代码,然后通过网络获得客户端输入的用户名和密码,进行验证,验证通过,则获得shell。

  

 

          图片来自unix环境高级编程217页

   登录成功后其实做了很多事情,如图:①工作目录改为用户的家目录,②改变(伪)终端的所有权,③设置进程组ID(重要),④用户环境变量,调用shell等等。

    

 

posted @ 2019-11-26 20:55  Ccluck_tian  阅读(229)  评论(0编辑  收藏  举报