《UNIX环境高级编程》学习笔记四 —— 进程环境、进程控制

本文详细解析了C程序如何从main函数启动,进程的正常与异常终止方式,包括使用exit与_exit函数的区别。深入探讨了C程序的存储空间布局,如正文段、数据段、栈和堆的分配。讲解了进程标识、创建新进程的方法,如fork函数,以及wait和waitpid函数用于回收子进程。最后,介绍了进程间通信的基础,如管道的使用及其局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、main函数

       C程序总是从main函数开始执行,main函数原型是:

                                                             int  main ( int  argc,  char  *argv[] );

       其中,argc是命令行参数的数目,argv是指向参数的各个指针所构成的数组。

       当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址。启动例程从内核获取命令行参数和环境变量值,然后为按上述方式调用main函数做好安排。(类似线程函数的调用方式)

 

二、进程终止

        有8种方式使进程终止。其中5种为正常终止,它们是:

        1.从main返回;

        2.调用exit;

        3.调用_exit或_Exit;

        4.最后一个线程从其启动例程返回;

        5.最后一个线程调用pthread_exit()。

        异常终止有5种,它们是:

        1.调用abort;

        2.接到一个信号;

        3.最后一个线程对取消请求做出相应。

 

        如果将启动例程以C代码形式表示(实际该例程常常用汇编语言编写),则调用main函数的形式可能是:

                                                                 exit (main(argc, argv)

 

1.退出函数

         #include  <stdlib.h>

         void  exit(int  status);

         void  _Exit(int  status);

         #include  <unistd.h>

         void  _exit(int  status);

 

        3个函数用于正常终止一个程序。_exit和_Exit立即进入内核,exit则先执行一些清理处理,然后返回内核。

        3个退出函数带的整形参数成为终止状态或退出状态。如果调用退出函数时不带终止状态,或者main函数执行了一个无返回值的return语句,或者main函数没有声明返回类型为整型,则该进程的终止状态是未定义的;如果main函数的返回类型是整形,且执行到最后一条语句时返回,那么该进程的终止状态是0。

                                                                    echo  $?       返回上一条命令的终止状态

        注: 将main声明为返回整形,但在main函数体内用exit代替return,对某些C编译器和UNIX程序会产生不必要的警告,因为这些编译器不了解main中exit与return语句的作用相同。解决方法一:在main中使用return语句;解决方法二:将main说明为void而不是int。POSIX 1和ISO C定义main表示返回整形

2.一个C程序是如何启动和终止的

 

三、C程序存储空间布局

       1.正文段:CPU执行机器指令部分‘

       2.初始化数据段:比如 int  maxcount  =  99;

       3.未初始化数据段:比如 int  sum[1000];

       4.栈:自动变量和每次函数调用所需保存的信息

       5.堆:动态储存分配

 

四、存储空间分配

       #include  <stdlib.h>

       void  *malloc(size_t  size);

       void  *calloc(size_t  nobj,  size_t  size);

       void  *realloc(void  *ptr,  size_t  newsize);

       void  *free(void  *ptr);

 

        malloc分配指定字节数的存储区,初始值不确定。

        calloc为指定数量指定长度的对象分配存储空间,初始值为0。

        realloc增加或减少以前分配区的长度,新增区域的初始值不确定。

        free释放ptr指向的存储空间。

 

五、进程标识

        进程ID是唯一的,但可以复用。大多数UNIX系统采用延迟复用算法,使得赋予新建进程的ID不同于最近终止进程所使用的ID,防止将新进程误认为是使用同一ID的旧进程。

        #include  <unistd.h>

        pid_t  getpid(void);                      返回调用进程的ID

        pid_t  getppid(void);                    返回调用进程的父进程的ID

 

六、创建新进程

        #include  <unistd.h>

        pid_t  fork(void);

        子进程返回0;父进程返回子进程ID;出错返回-1。

        

        子进程和父进程继续执行fork调用之后的指令(从返回值开始,所以fork返回两次,一次是子进程返回,一次是父进程返回)。父进程和子进程共享正文段,不共享存储空间部分。同时,父子进程遵循共享变量读时共享写时复制原则

 

         创建新进程有其他函数vfork,但在可移植应用程序中不应该使用这个函数。

       

七、wait和waitpid

         #include  <sys/wait.h>

         pid_t  wait(int  *statloc);

         pid_t  waitpid(pid_t  pid, int  *statloc, int  options);

        

        statloc是一个整形指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内,可通过一些宏调用显示终止状态;如果不关心终止状态,则可将该参数指定为空指针。

 

     wait函数必须阻塞到一个子进程终止,才会继续执行下一步操作;waitpid可指定等待某个子进程的终止,也可以选择不阻塞。

     wait函数功能:1.阻塞等待子进程退出;

                              2.回收子进程残留资源;

                              3.获取子进程结束状态(退出原因)

     waitpid参数pid :            > 0  回收指定ID的进程    

                                             -1   回收任意子进程 

                                            0    回收和当前调用waitpid一个组的所有子进程   

 

八、gdb调试

                    set  follow-fork-mode  parent    设置跟踪父进程(默认) 

                   set  follow-fork-mode  child    设置跟踪子进程

 

九、进程中调用新进程(但当前进程ID不会改变

 

十、回收进程

    孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程。子进程的父进程变成init进程,成为init进程领养孤儿进程。

    僵尸进程:子进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程。(kill无法清除僵尸进程)   

十一、进程间通信方式

             管道:使用最简单

             信号:开销最小

             共享映射区:无血缘关系:

             本地套接字:最稳定

 

十二、管道

              管道本质是一个内核缓冲区(伪文件);

              由两个文件描述符引用,一个表示读,一个表示写(单向的);

  局限性:

               1.数据不能自己写自己读;

               2.一旦读走就不在管道中;

               3.管道采用半双工通信;

               4.只能在有公共父端的进程间使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值