Linux之进程的创建、终止和等待

文章详细介绍了Linux中进程的创建,主要通过fork函数实现,包括子进程与父进程的关系及fork的返回值。接着讨论了进程的终止,包括正常和异常退出,以及退出码的概念。最后,讲述了进程的等待机制,如wait和waitpid函数的使用,用于父进程回收子进程并获取其退出状态,防止僵尸进程的产生。

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

一、进程的创建

1.fork函数

fork 函数能够从已存在进程中创建一个新进程,新进程为子进程,而原进程为父进程。进程调用 fork 函数后,操作系统会做一下的事情:

1.创建子进程,操作系统需要为子进程分配新的内核数据结构和内存块

2.拷贝父进程的虚拟地址空间,但映射到物理内存时采用写时拷贝

3.共享父进程fork之后的代码,而数据分离(代码是只读的,代码共享并不影响进程的独立性)

4.添加子进程到系统进程列表中

5.fork返回,开始由调度器调度

2.fork函数的返回值

子进程返回0;

父进程返回子进程的pid;

3.fork失败的原因

1.系统中有太多的进程

2.实际用户的进程数超过了限制

二、进程的终止

1.进程退出的场景

1.代码运行结束,结果正确

2.代码运行结束,结果错误

3.代码异常终止

2.进程的退出码

.我们常在main函数的后面加一句return 0,实际上,0就是这个进程的退出码,return 0就代表的是: 程序结束,且正常退出。非0: 代表程序正常退出且结果有误。

通过调用strerror函数可以查看所有的进程退出码

 在Linux中也可以通命令行echo $?查看上一个进程的进程退出码

三、进程的等待

1.为什么要等待

       子进程退出,父进程如果不管不顾,就可能造成僵尸进程的问题,进而造成内存泄漏。 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对, 或者是否正常退出。 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。

2.如何等待

wait

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

返回值: 成功返回被等待进程pid,失败返回-1。

参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
 
//让父进程通过使用wait系统调用阻塞式的等待回收子进程
int main()
{
  pid_t id = fork();
  if(id == 0)
  {
    //子进程
    int count = 3;
    while(count)
    {
      printf("I am child, 我将在%d秒后结束, 我的pid: %d\n", count, getpid());
      count--;
      sleep(1);
    }
  }
  else
  {
    //父进程
    printf("I am father, 我开始等待回收子进程\n"); 
    pid_t res = wait(NULL);
    if(res > 0)
    {
      printf("I am father, 等待子进程(pid: %d)成功\n", res);
    }
    else if(res == -1)
    {
      printf("I am father, 等待子进程失败\n");
    }
  }
  return 0;
}

运行结果如下

 

wait的参数只有一个, 是一个输出型参数, 当调用wait回收子进程时, 会将子进程的退出状态填入这个输出型参数中,这个输出型参数status是一个32位的数字, 低七位存放信号部分(第8位先不考虑), 次低八位存放退出码。

当程序正常退出, 则信号部分将不被关心

当程序异常崩溃, 则退出码部分将不被关系(异常崩溃的本质就是操作系统给这个异常进程发送了信号并且强制终止)

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
 
//让父进程通过使用wait系统调用阻塞式的等待回收子进程
int main()
{
  pid_t id = fork();
  if(id == 0)
  {
    //子进程
    int count = 3;
    while(count)
    {
      printf("I am child, 我将在%d秒后结束, 我的pid: %d\n", count, getpid());
      count--;
      sleep(1);
    }
    exit(55);//子进程结束, 退出码为55
  }
  else
  {
    //父进程
    int status = 0;
    printf("I am father, 我开始等待回收子进程\n"); 
    pid_t res = wait(&status);
    if(res > 0)
    {
      printf("I am father, 等待子进程(pid: %d)成功\n", res);
      printf("wait中输出型参数status:%d\n", status);
      printf("status中的次低八位(退出码): %d\n", (status >> 8) & 0xFF);
      printf("status中的低七位(信号): %d\n", status & 0x7F);
    }
    else if(res == -1)
    {
      printf("I am father, 我回收子进程失败\n");
    }
  }
  return 0;
}

子程序正常退出情况

子程序异常退出情况

 waitpid

pid_ t waitpid(pid_t pid, int *status, int options);

参数:

第一个参数pid:

        pid > 0, 回收为对应pid的子进程

        pid == -1, 回收任意一个子进程

第二个参数status:

        与wait的参数是同一个, 都是输出型参数

第三个参数options:

        options传参为0: 阻塞式的等待回收子进程

        options传参为WNOHANG: 非阻塞式的等待回收子进程

        (WNOHANG是一个宏, #define WNOHANG 1)

返回值:

回收子进程成功, 返回子进程的pid

回收子进程过程中出错, 返回-1

如果使用非阻塞等待(WNOHANG)式的调用, 子进程还未结束, 返回0

两个宏函数

WIFEXITED(status): 若正常终止子进程返回状态, 则为真 (判断子进程是否是正常退出的)

WEXITSTATUS(status): 若子进程是正常退出的, 则表示正常退出的退出码
 

#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
 
//让父进程通过使用wait系统调用阻塞式的等待回收子进程
int main()
{
  pid_t id = fork();
  if(id == 0)
  {
    //子进程
    int count = 3;
    while(count)
    {
      printf("I am child, 我将在%d秒后结束, 我的pid: %d\n", count, getpid());
      count--;
      sleep(1);
    }
    //观察进程崩溃(异常退出)
    //int *p = NULL;
    //*p = 10;
    exit(55);
  }
  else
  {
    //父进程
    int status = 0;
    printf("I am father, 我开始等待回收子进程\n"); 
    //阻塞式等待
    pid_t res = waitpid(id, &status, 0);
    if(res > 0)//子进程回收成功
    {
      if(WIFEXITED(status))//子进程正常退出
      {
        printf("I am father, 等待子进程(pid: %d)成功\n", res);
        printf("子进程正常退出且退出码为: %d\n", WEXITSTATUS(status));
      }
      else//子进程异常退出
      {
        printf("I am father, 等待子进程(pid: %d)成功\n", res);
        printf("子进程异常退出且信号为: %d\n", status & 0x7F);
      }
    }
    else if(res == -1)//子进程回收失败
    {
      printf("子进程回收失败\n");
    }
  }
  return 0;
}

运行结果如下

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值