Linux——进程管理核心操作与原理总结(二)-CSDN博客https://blog.csdn.net/wy_05136/article/details/160186035?sharetype=blogdetail&sharerId=160186035&sharerefer=PC&sharesource=wy_05136&spm=1011.2480.3001.8118

一、进程退出:exit() VS _exit()

exit() _exit()
类型 C标准库函数 Unix系统调用函数
作用 结束当前进程 结束当前进程,但是会将缓冲区内容清空
核心行为

会执行用户的资源清理操作,再调用内核级别的进程终止逻辑。

执行步骤:

1.执行用户注册的"退出处理函数"

2.刷新并关闭标准I/O缓冲区(把缓冲区内容强制刷新到终端或文件中)

3.清理进程的私有资源

4.调用_exit()触发内核回收

直接出发内核回收,会跳过所有的用户态操作,直接通知内核结束进程。

不执行"退出处理函数";不执行刷新标准I/O缓冲区。

标准I/O缓冲区 强制刷新并关闭 不刷新,直接丢弃数据
用法

1.普通单进程程序,优先使用exit()

2.多进程程序(父/子进程),子进程优先使用_exit(),避免干扰父进程的用户态资源,父进程使用eixt()

二、printf函数输出问题

printf函数不会直接将数据输出到屏幕,而是先放到缓冲区中;只有满足以下情况,才会输出到屏幕。

(1)缓冲区满

(2)强制刷新缓冲区:调用fflush(stdout)(输出到屏幕)或者fflush(文件指针)(输出到文件)

(3)进程结束

(4)遇到换行符\n

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
int main() 
{ 
    printf("hello"); 
    //fflush(stdout); 
    /*
    1.若执行此语句,则会强制刷新缓冲区,运行结果:直接输出hello
    2.若不执行语句,运行结果:等进程结束后再输出hello
    */
    sleep(3); 
    exit(0); 
} 

三、主函数参数介绍

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

argc:参数个数

argv:参数内容

envp:环境变量

四、复制进程 fork()

fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。 

1.头文件:<unistd.h>

2.函数原型:pid_t fork(void);

3.函数返回类型:pid_t ,实质是 int 类型

4.返回值:有三种返回情况

(1)在父进程中,返回子进程的PID(正整数),用于父进程的识别和子进程的管理。

(2)在子进程中,PID的返回值是0,用于确认子进程的身份。

(3)如果返回-1,表示fork失败;失败原因:内存不足 或者 系统进程数达到上限;设置错误原因给到系统全局变量errorno,表示错误原因。

注意:

1.子进程会完全复制父进程的所有内容(包括缓冲区、变量、代码段);

2.父子进程独立运行,执行顺序由操作系统调度决定。

五、僵死进程 & 孤儿进程

1.僵死进程

子进程先于父进程结束,父进程没有获取子进程的退出码,子进程会变成僵死进程。

defunct表示该进程成为僵死进程。

2.如何处理僵死进程?

父进程通过调用wait()完成。

wait():让父进程等待子进程结束,然后获取子进程退出码,避免僵死进程

exit():让进程退出,参数为该进程的退出码


退出码是以二进制形式存储的,如何获取十进制退出码呢?

方法一:右移8位用%d打印

方法二:使用宏函数

WIFEXITED:判断进程是否正常退出,返回值为true或false

WEXITSTATUS:获取进程的正常退出码

3.孤儿进程

父进程先于子进程结束,子进程会变成孤儿进程,从而被进程资源管理器接管后继续运行。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐