Linux进程控制(2)

简介: Linux进程控制(2)

二、进程终止


1、退出码


概念:

其实main函数是间接性被操作系统所调用的,当main函数调用结束后就应该给操作系统返回相应的退出信息,而这个所谓的退出信息就是以退出码的形式作为main函数的返回值返回


我们一般以0表示代码成功执行完毕,以非0表示代码执行过程中出现错误,一般来说我们写的代码都不太规范,没有根据执行结果返回相应的退出码


注:退出码可以人为定义,也可以使用系统的错误码表


示图:系统错误码表


退出码查看:

使用指令 echo $?


示例:


注:如果main没有return,则echo $?查看的是最近函数的退出码,一般来说都是0


2、退出方法


  • 进程退出场景:


  1. 代码运行完毕,结果正确,退出码为0
  2. 代码运行完毕,结果不正确,逻辑存在问题,退出码为非0
  3. 代码异常终止,层序崩溃,退出码没有意义


  • 进程常见退出方法:


1) 调用_exit函数


  • _exit函数原型:


#include <unistd.h>
void _exit(int status);


  • 注意:
  1. status 定义了进程的终止状态,父进程通过wait来获取该值
  2. 虽然status是int,但是仅有低8位可以被父进程所用

注:_exit(-1)时,在终端执行$?发现返回值是255

  • 示图:


2)调用exit函数


  • exit函数原型:


#include <unistd.h>
void exit(int status);


exit与_exit的区别:

_exit仅仅是退出进程


exit在退出进程前,先执行用户通过 atexit或on_exit定义的清理函数,关闭所有打开的流,所有的缓存数据均写入(刷新缓冲区),最后调用_exit


示图:


示例:


3)main函数return



return是一种更常见的退出进程方法,执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做exit的参数


示图:


注意:

只有是在main函数的的return才算是终止进程,其他函数return只是结束函数,因为系统调用的是main函数,main函数返回才是进程的返回


调用main函数运行结束后,main函数的return返回值当做exit的参数来调用exit函数,而使用exit函数退出进程前,exit函数会先执行用户定义的清理函数、冲刷缓冲,关闭流等操作,然后再调用_exit函数终止进程


4)异常退出

向进程发生信号

如在进程运行过程中向进程发生kill -9信号使得进程异常退出,或是使用Ctrl+C迫使进程退出


代码运行异常

如代码当中存在野指针问题等bug问题使得进程运行时异常退出


3、理解终止

以OS角度理解:核心思想-归还资源

释放曾经为管理进程所维护的数据结构资源,并非销毁释放数据结构对象,而是将状态设置为无效并保存起来,下一次需要就直接使用不用申请,相当于建立对应的数据结构“内存池”


释放程序数据和代码占用的空间,并非清空数据和代码,而是将对应内存区域设置为无效,要再次使用时直接覆盖数据和代码就行了


取消曾经该进程在进程队列里的链接关系(避免”野指针“)


三、进程等待


进程等待必要性:

当子进程退出,并不是完全退出,子进程的PCB任然存在,父进程如果不等待回收,就可能造成‘僵尸进程’的问题,进而造成内存泄漏


注:进程一旦变成僵尸状态,并不能被父进程给kill掉,因为子进程已经死去,只能父进程等待回收


子进程的PCB保留着退出前任务执行的信息,而通过回收子进程我们可以知道子进程运行完成,结果对还是不对,或者是否正常退出


注:非必须,依执行的程序和需求而定


尽量使父进程晚于子进程退出,可以规范化进行资源的回收


注:所以一般来说,当我们fork之后,就需要父进程等待回收子进程


1、等待方法

wait方法:

wait函数原型:


#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);


  • 注意:


  1. wait函数作用的等待任意子进程
  2. 返回值:成功返回被等待进程pid,失败返回-1
  3. 参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL


  • waitpid方法:


waitpid函数原型:



#include<sys/types.h>
#include<sys/wait.h>
pid_ t waitpid(pid_t pid, int *status, int options);


注意:

返回值:


当正常返回的时候waitpid返回收集到的子进程的进程ID


如果设置了选项options为WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在


参数pid:


Pid=-1,等待任一个子进程,与wait等效


Pid>0,等待其进程ID与pid相等的子进程


参数status:


参数status是一个输出型参数,需要我们传入一个整形变量的地址,以此获取子进程退出的信息


使用对应的宏可以查看我们需要的退出信息:WIFEXITED(status): 若为正常终止子进程返回的状态,则为真(查看进程是否是正常退出);WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码(查看进程的退出码)


参数options:


设置为0:表示默认的阻塞式等待子进程退出,即子进程没退出就不返回,一直等待到子进程退出回收子进程


设置为WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待;若正常结束,则返回该子进程的ID


示例1:阻塞等待


#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    pid_t id=fork();
    if(id==0)
    {
        printf("I am child process:  pid:%d ppid:%d\n",getpid(),getppid());
        sleep(5);
       // int* p=12345;
       // *p=100;//野指针
        exit(123);
    }
    printf("father wait...\n");
    int status=0;
    //pid_t ret=wait(&status);//等待特定任意子进程
    pid_t ret=waitpid(id,&status,0);//阻塞等待特定子进程
    if(ret>0&&WIFEXITED(status))//等待成功并子进程退出正常
    {
        printf("wait success: wait for id:%d status code:%d\n",ret,WEXITSTATUS(status));
    }
    else if(ret>0)//等待成功但是子进程退出异常
    {
        printf("exit error! status codedump:%d sign:%d\n",(status>>7)&1,status&0x7F);
    }
    return 0;
}


image.png



相关文章
|
1天前
|
存储 安全 Linux
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
【Linux】详解进程通信中信号量的本质&&同步和互斥的概念&&临界资源和临界区的概念
|
1天前
|
消息中间件 算法 Linux
【Linux】详解如何利用共享内存实现进程间通信
【Linux】详解如何利用共享内存实现进程间通信
|
1天前
|
Linux
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
|
1天前
|
Linux
【Linux】匿名管道实现简单进程池
【Linux】匿名管道实现简单进程池
|
1天前
|
Linux
【Linux】进程通信之匿名管道通信
【Linux】进程通信之匿名管道通信
|
1天前
|
Linux C++
【Linux】详解进程程序替换
【Linux】详解进程程序替换
|
1天前
|
存储 Linux Shell
Linux:进程等待 & 进程替换
Linux:进程等待 & 进程替换
27 9
|
1天前
|
存储 Linux C语言
Linux:进程创建 & 进程终止
Linux:进程创建 & 进程终止
23 6
|
1天前
|
存储 安全 Linux
Linux:进程地址空间
Linux:进程地址空间
20 10
|
1天前
|
存储 弹性计算 Linux
Linux:进程调度
Linux:进程调度
19 7