当前位置: 首页 > news >正文

湘潭建网站网络营销与直播电商

湘潭建网站,网络营销与直播电商,企业网站的优缺点,怎么用网页源码做网站目录 0.前言 1. 进程终止 1.1 进程退出的场景 1.2 进程常见退出方法 1.2.1 正常退出 1.2.2 异常退出 2. 进程等待 2.1 进程等待的重要性 2.2 进程等待的方法 2.2.1 wait() 方法 2.2.2 waitpid() 方法 2.3 获取子进程 status 2.4 阻塞等待和非阻塞等待 2.4.1 阻塞等待 2.4.2 非阻…

目录

0.前言

1. 进程终止

1.1 进程退出的场景

1.2 进程常见退出方法

1.2.1 正常退出

1.2.2 异常退出

2. 进程等待

2.1 进程等待的重要性

2.2 进程等待的方法

2.2.1 wait() 方法

2.2.2 waitpid() 方法

2.3 获取子进程 status

2.4 阻塞等待和非阻塞等待

2.4.1 阻塞等待

2.4.2 非阻塞等待

3.结语


(图像由AI生成) 

0.前言

在上一个博客中,我们介绍了如何通过 fork() 函数创建子进程。子进程创建后,通常会执行一些任务,然后终止。而父进程在子进程终止后,需要适当的方式来处理和等待子进程的退出。本文将详细讨论 Linux 中进程的终止与进程等待的相关内容。

1. 进程终止

进程终止是操作系统管理进程生命周期的重要阶段,当进程完成其预定的任务或遇到意外时,它会终止并向系统报告其退出状态。理解进程如何正常或异常终止,对于开发人员和系统管理员进行进程管理至关重要。

1.1 进程退出的场景

进程的退出场景可以大致归纳为以下三种:

  • 代码运行完毕,结果正确:进程执行完所有任务并成功返回预期结果。
  • 代码运行完毕,结果不正确:进程虽然执行结束,但由于逻辑错误或其他原因导致输出结果与预期不符。
  • 代码异常终止:进程在执行过程中发生了未预期的错误,导致进程崩溃或被系统强制终止。

虽然进程退出的原因和场景各异,但所有进程最终都会通过一定的机制向系统报告其结束状态。

1.2 进程常见退出方法

进程退出的方式大致分为两类:正常退出和异常退出。我们可以通过不同的系统调用或外部信号来结束进程。

1.2.1 正常退出

在进程正常退出的情况下,它的生命周期如预期完成,并返回特定的状态码,表示程序执行成功或失败。常见的正常退出方法如下:

  1. main() 函数返回: 在 C/C++ 语言中,进程的入口点是 main() 函数。当程序执行完毕并到达 main() 的结束处,进程会通过 return 语句返回一个状态码,向系统报告其退出状态。典型地,return 0 表示正常退出,而非零值(如 return 1return -1)表示出现了某些错误。

    int main() {// ... 业务逻辑return 0;  // 正常退出
    }
    
  2. 调用 exit()exit()标准库函数,允许程序随时结束执行,并返回状态码。调用 exit() 后,程序会执行清理操作,例如关闭打开的文件、释放资源,并调用通过 atexit() 注册的回调函数。exit() 通常用于程序需要在特定条件下主动退出时。

    #include <stdlib.h>
    int main() {// ... 业务逻辑if (某种错误发生) {exit(1);  // 异常退出}exit(0);  // 正常退出
    }
    
  3. 调用 _exit()_exit()系统调用,通常在子进程中使用。与 exit() 不同,_exit() 不会执行缓冲区的刷新或已注册的清理函数,它直接向内核报告进程结束并释放其资源。通常在子进程完成其工作后,调用 _exit() 立即退出。

    #include <unistd.h>
    int main() {if (fork() == 0) {// 子进程执行_exit(0);  // 立即退出}// 父进程继续执行return 0;
    }
    

1.2.2 异常退出

异常退出是指进程在非预期情况下由于错误或外部干预而终止。常见的异常退出方式包括:

  1. Ctrl+C(信号终止): 当用户在命令行按下 Ctrl+C,系统会发送 SIGINT 信号给进程,指示其立即终止。这是一种外部干预的方式,常用于终止长时间运行的任务。

    ./your_program
    # 用户按下 Ctrl+C,程序收到 SIGINT 信号并终止
    
  2. 异常信号终止: 进程可能由于内部错误(如访问无效内存地址)而收到操作系统发送的异常信号,导致进程非正常退出。常见的异常信号包括 SIGSEGV(段错误)、SIGFPE(算术错误,如除零)等。

    例如,非法内存访问会导致 SIGSEGV 信号:

    int main() {int *ptr = NULL;*ptr = 42;  // 导致段错误,异常退出return 0;
    }
    

当进程因信号终止时,系统会向父进程报告该终止信号,而不是正常的退出状态码。开发者可以通过适当的信号处理机制捕捉并处理这些信号,避免进程非预期崩溃。

2. 进程等待

当子进程终止时,父进程需要进行适当的处理,避免出现僵尸进程。僵尸进程不仅会占用系统的进程表条目,还会导致内存资源无法及时回收。因此,父进程通过进程等待机制来回收子进程资源,并获取子进程的退出状态。

2.1 进程等待的重要性

当子进程结束后,如果父进程不主动等待并回收子进程资源,就可能导致子进程进入僵尸状态。僵尸进程的特性是已经终止,但仍然在系统的进程表中保留一些信息,包括退出状态。由于这些进程已经结束,系统资源无法通过常规的手段释放。

  • 僵尸进程占用系统资源,并且无法被终止。即使使用 kill -9 这样的强制终止信号,也无法“杀死”一个已经处于僵尸状态的进程,因为它已然是“死去的进程”。
  • 另外,父进程往往需要知道子进程任务完成的情况,例如子进程是否正常退出,返回结果是否正确。这些信息对父进程判断后续操作具有重要意义。

因此,父进程通过等待机制能够:

  1. 回收子进程的资源,避免僵尸进程;
  2. 获取子进程的退出状态,了解子进程的执行结果。

2.2 进程等待的方法

Linux 提供了几种等待子进程的方法,最常见的有 wait()waitpid() 函数。

2.2.1 wait() 方法

wait() 是一个简单的进程等待函数,父进程通过调用 wait() 可以阻塞自身,直到有一个子进程终止。它的基本使用方式如下:

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
  • 返回值:成功时,返回已终止的子进程的 PID;如果发生错误,返回 -1
  • 参数
    • status:指向一个整数的指针,用于存储子进程的退出状态。如果不关心子进程的退出状态,可以将该参数设置为 NULL

wait() 函数适用于父进程只需等待任意一个子进程退出的场景。当父进程有多个子进程时,wait() 将会等待其中的任何一个结束,并返回它的进程 ID。

2.2.2 waitpid() 方法

waitpid()wait() 的增强版本,提供了更多的功能和灵活性。例如,父进程可以通过 waitpid() 等待特定的子进程,或者选择非阻塞等待。其函数定义如下:

pid_t waitpid(pid_t pid, int *status, int options);
  • 返回值

    • 如果成功,waitpid() 返回终止的子进程的 PID。
    • 如果设置了 WNOHANG 选项且没有任何子进程终止,返回 0
    • 如果发生错误,返回 -1,并设置 errno 以指示错误原因。
  • 参数

    • pid
      • pid = -1:等待任意子进程终止,功能与 wait() 相同。
      • pid > 0:等待指定 PID 的子进程终止。
    • status:与 wait() 中类似,保存子进程的退出状态。可以通过 WIFEXITED(status) 判断子进程是否正常终止,使用 WEXITSTATUS(status) 提取退出码。
    • options
      • WNOHANG:如果没有子进程终止,则 waitpid() 立即返回,而不会阻塞父进程。这对于父进程需要同时处理其他任务时非常有用。

2.3 获取子进程 status

在使用 wait()waitpid() 等待子进程时,除了能够回收子进程的资源,还可以通过 status 参数获取子进程的退出信息。这个参数是一个输出型参数,由操作系统填充,用来向父进程反馈子进程的退出状态。

status 参数的使用

  • status 的意义: 当我们调用 wait()waitpid() 时,status 参数是一个用于存储子进程退出状态的变量。如果我们不关心子进程的退出状态,可以将这个参数设置为 NULL。然而,如果我们希望获得子进程的退出信息,需要提供一个指针,操作系统会将退出信息写入该地址。

  • 位图解读status 参数并不是一个简单的整形值,而是一个位图,通常我们只需要关心它的低 16 位。其中,最常用的信息包括:

    • 子进程是否正常退出;
    • 子进程的退出码;
    • 如果是异常终止,是什么信号导致的异常终止。

当子进程正常退出时,status 中的高位(第 8 到第 15 位)存储了子进程的退出码,而低 7 位(第 0 到第 6 位)用于表示子进程的信号终止信息。

  • 正常退出:如果子进程是通过 exit()return 正常退出,status 的低 7 位应该是 0,表示没有通过信号终止。此时,高位存储的是子进程的退出码,可以通过 st >> 8 提取。

  • 异常终止:如果子进程因为信号而被终止,低 7 位会存储导致终止的信号编号。父进程可以通过 st & 0X7F 获取到信号编号,进一步判断子进程因何信号终止。

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main() {pid_t pid;if ( (pid=fork()) == -1 ) {perror("fork"), exit(1);}if (pid == 0) {// 子进程休眠20秒后正常退出,退出码为10sleep(20);exit(10);} else {// 父进程等待子进程退出int st;int ret = wait(&st);if (ret > 0 && (st & 0X7F) == 0) { // 正常退出printf("child exit code:%d\n", (st >> 8) & 0XFF);} else if (ret > 0) { // 异常退出printf("sig code : %d\n", st & 0X7F);}}
}

测试结果

  1. 当子进程正常退出时,输出如下:

     

    子进程正常退出,父进程通过 status 获取子进程的退出码为 10

  2. 当子进程在其他终端被 kill 掉时,输出如下:

     

    这是因为子进程被 SIGKILL 信号(编号为 9)终止,父进程通过 status 获取到了导致子进程终止的信号编号。

2.4 阻塞等待和非阻塞等待

在进程等待时,父进程可以选择采用阻塞等待或者非阻塞等待的方式来处理子进程的退出。阻塞等待会使父进程在子进程退出前一直处于等待状态,而非阻塞等待则允许父进程在子进程未退出时继续执行其他任务。

2.4.1 阻塞等待

阻塞等待是最常见的等待方式。当父进程调用 wait()waitpid() 并不设置任何非阻塞选项时,父进程会一直等待直到有子进程退出。此时,父进程会被阻塞,无法进行其他操作。

代码示例

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");exit(1);}if (pid == 0) {  // 子进程printf("Child process running...\n");sleep(5);  // 子进程休眠5秒模拟任务执行printf("Child process finished.\n");exit(0);} else {  // 父进程int status;printf("Parent waiting for child to exit (blocking)...\n");wait(&status);  // 阻塞等待子进程结束printf("Child exited with status: %d\n", WEXITSTATUS(status));}return 0;
}

输出结果

  • 父进程在子进程运行期间被阻塞,直到子进程结束后才继续执行。
 

2.4.2 非阻塞等待

非阻塞等待允许父进程在等待子进程时继续执行其他任务,而不是阻塞等待子进程结束。通过在 waitpid() 中传入 WNOHANG 选项,父进程可以立即返回,即使子进程还没有结束。

代码示例

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();  // 创建子进程if (pid == -1) {perror("fork failed");exit(1);}if (pid == 0) {  // 子进程printf("Child process running...\n");sleep(5);  // 子进程休眠5秒模拟任务执行printf("Child process finished.\n");exit(0);} else {  // 父进程int status;printf("Parent checking child status (non-blocking)...\n");while (1) {pid_t result = waitpid(pid, &status, WNOHANG);  // 非阻塞等待if (result == 0) {// 子进程还没有结束printf("Child process is still running...\n");sleep(1);  // 父进程继续执行其他任务} else if (result == -1) {perror("waitpid failed");exit(1);} else {// 子进程结束printf("Child exited with status: %d\n", WEXITSTATUS(status));break;}}}return 0;
}

输出结果

  • 父进程每隔 1 秒检查一次子进程状态,而不会阻塞自己等待子进程结束。当子进程结束时,父进程获取子进程的退出状态并结束循环。

3.结语

Linux 系统中的进程终止和进程等待是进程管理中的核心内容。通过合理地终止进程并及时进行等待操作,父进程可以有效地处理子进程的退出,避免产生僵尸进程,同时保证系统资源的高效利用。希望通过本文的讲解,读者能够对进程终止和进程等待有更深入的理解。

http://www.khdw.cn/news/5233.html

相关文章:

  • php 网站进入后台百度搜索引擎的功能
  • 众鱼深圳网站建设什么公司适合做seo优化
  • 农安建设局网站重庆森林电影
  • 如何做网站301重定向天天seo伪原创工具
  • 自己做的网站首页变成符号了日喀则网站seo
  • 专业的手机价格网站建设东莞网站推广公司黄页
  • 找家里做的工作到什么网站百度网盘客服在线咨询
  • 制作平台网站费用企业产品推广运营公司
  • 网站空间商排行榜比较好用的搜索引擎
  • 哪个视频网站做自媒体怎么开网站平台
  • 百度做网站要多久免费顶级域名申请网站
  • 世界500强企业招聘网站百度怎么提交收录
  • 建设信用中国网站的目的怎样做百度推广网页
  • 给个网站靠谱点2021关键词搜索量查询
  • 在什么网站可以自承包活来做内部搜索引擎优化
  • 山东省高中生发展报告在哪个网站做网络销售技巧和话术
  • 集团公司网站推广方案怎么做搜索引擎营销方法主要有三种
  • 怎么在网站上做模式题库今日热点新闻事件摘抄
  • 百度短网址seo学院
  • 怎样做浏览的网站不被发现长沙官网seo技术厂家
  • wordpress条文件夹百度seo软件曝光行者seo
  • 网站软件有哪些做销售怎么和客户聊天
  • 荔湾区做网站公司搜索引擎哪个最好用
  • 自己做网站地图搜索引擎优化案例
  • 做便宜网站现在有什么推广平台
  • 郑州金水区网站建设今日的新闻头条10条
  • 企业邮箱免费版注册关键词seo公司推荐
  • 湖北高端网站建设宁波seo排名优化培训
  • wordpress在线上传头像网站seo收费
  • 武汉网站seo设计关键词免费网站