• 【Linux】---进程控制(创建、终止、等待、替换)


    进程创建

    fork()

    fork函数在之前的文章中也已经提到过了。其主要作用是从已存在的进程中创建一个新的进程,也就是新建的进程为子进程,原进程为父进程

    当一个进程调用fork函数后,内核会做几件事:

    1. 分配新的内存块和内核数据结构给子进程
    2. 将父进程部分数据结构内容拷贝给子进程
    3. 添加子进程到系统进程列表中
    4. fork返回后,开始调度器调度

    下面来看看进程创建的一段简单代码

    #include
    #include
    #include
    
    int main(){
       
        pid_t id = fork();
        
        if(id == 0){
       
            printf("I am child process, pid = %d, ppid = %d\n", getpid(), getppid());
        }
        
        printf("I am parent process, pid = %d, ppid = %d\n", getpid(), getppid());
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    image-20221128143753830

    当其返回值为0时,说明创建出了子进程。

    进程退出

    进程退出场景

    进程退出总共会有三种情况,也就是我们平常写代码执行的时候也是会遇到这三种情况:

    1. 代码运行完毕,结果正确
    2. 代码运行完毕,结果不正确
    3. 代码遇到异常终止执行

    进程退出方法

    对于进程退出而言,可以有两种方法退出。一种就是正常的程序运行完毕终止执行,另一种就是程序遇到异常信号终止运行。

    那么现在有一个问题,我们平常写代码的时候为什么总是会带上一个 return 0 呢?这里就涉及到一个知识点—退出码

    退出码

    其实return 0这个0并没有什么特殊的意思,返回的是0就代表着程序执行正常退出,非0就是程序有错误,每一个非0的退出码都代表着不同的错误信息。可以通过程序看看

    #include
    #include
    
    int main(){
       
    	for(int i = 0; i < 20; i++)
    		printf("%d: %s\n", i, strerror(i));
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    image-20221128145109320

    exit、_exit

    那么除了return可以返回退出码退出程序外,exit和**_exit**也是可以的。不过这两者之间还是会有所区别的。

    1. exit是库函数,_exit是系统调用
    2. exit会刷新缓冲区,_exit不会

    进程等待

    进程等待是非常重要的。之前在进程状态里面谈到了一种状态—僵尸状态。这种状态是非常危险的,会造成内存泄漏。并且一旦进程变成了僵尸状态,那么即使使用kill -9都无法将其杀死。

    所以父进程想要获取子进程的任务完成的程度如何,就必须通过进程等待的方式,回收子进程资源,获取子进程退出信息

    进程等待的方法

    进程等待有两种方法:1、阻塞等待;2、非阻塞等待。可以使用两个函数去实现:wait和waitpid

    image-20221128150111166

    wait

    wait等待成功会返回被等待的进程的pid,失败则返回-1,下面来一段代码感受一下

    #include
    #include
    #include
    #include
    #include
    #include
    
    int main(){
       
      pid_t id = fork();
    
      if(id == 0){
       
        int cnt = 5;
        while(cnt--){
       
          printf("I am child process, pid = %d\n", getpid());
          sleep(1);
        }
        exit(1);
      }
    
      pid_t ret = wait(NULL);
      printf("%d\n", ret);
    
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    image-20221128151017389

    可以看到进程最后打印出的是子进程的pid,说明等待成功了。

    waitpid

    waitpid 相对于 wait 来说能够获取的信息就更多了,可以获取子进程的退出码和子进程返回的状态。

    如果子进程是正常终止,那么返回的状态为0,如果收到了异常信号终止则非0

    但是这里还要注意的是,waitpid 返回的子进程的数据是有自己的存储方式的。例如 waitpid 返回了一个变量 status 那么这个变量的**高八位为退出状态,低八位为终止信号。

    image-20221128151748607

    如果进程是被信号所杀,则退出状态就没有用到,终止信号根据实际。如果进程正常终止,则退出状态根据实际,终止信号为0.

    所以当waitpid 返回了一个值,我们想要获取终止信号就得用这个值 & 0x7f;获取退出状态就得用这个变量 向右移动8位再 & 0xff

    来一段代码感受一下

    #include
    #include
    #include
    #
    • 1
    • 2
    • 3
  • 相关阅读:
    想要精通算法和SQL的成长之路 - 最长递增子序列 II(线段树的运用)
    使用C#窗体绘制动态曲线图
    软件测开记录(一)
    开源对象存储系统minio部署配置与SpringBoot客户端整合访问
    GitHub 曝出漏洞,或导致 4000 多个存储库遭受劫持攻击
    Flink安装及简单使用
    内网域环境搭建教程
    flv格式怎么转换成mp4,一键快速转换视频格式
    软件项目可行性研究报告
    避坑之路 —— 前后端 json 的注意问题
  • 原文地址:https://blog.csdn.net/weixin_52563203/article/details/128083278