【Linux】进程等待进程程序替换
啊,Linux进程管理,这可不是一件轻松的事儿,特别是对于新手来说。想象一下,你的程序像是一个调皮的孩子,而系统管理员就是家长,负责看护这些"孩子"。但你可别以为系统管理员就能轻轻松松,背后有很多技术支持,今天咱们就来聊聊进程等待和进程程序替换这两个好帮手。
问题来了:你是否知道子进程会在父进程前退出,留下"僵尸",让你的系统变成"鬼故事"?这种情况下,你会慌成什么样!
答案:这得用"进程等待"来收拾这些"僵尸"。就像家长在孩子离开时给予最后的拥抱,wait函数就像一个温暖的抱抱,等待子进程结束,然后收拾好它的状态信息。这可不仅仅是清理,而是要确保系统资源不被浪费。
再来看看另一个问题:当你想让程序执行不同的任务时,比如从bash切换到运行你自己的代码,该怎么办呢?这可不是换衣服那么简单,而是要进行“进程程序替换”。这就像换衣服时换了一个全新的自己,exec函数家族就是你的换装小能手。
想想这些机制是如何支撑后台进程,也就是守护进程的。它们就像系统里的"隐形人",默默工作,不被终端打扰。这背后的秘密正是进程等待和程序替换的完美配合。
举个栗子,想让你的进程像守护进程一样在后台运行吗?只要设置父进程在fork后wait,子进程通过exec执行新程序,配合SID和 PID的处理,就能自由自在地在后台工作啦!
总之,进程等待和替换这两个机制,像两个得力的助手,让你的程序在Linux系统中得以优雅地运行和管理。现在是不是觉得这些技术不再可怕呢?
进程等待&进程程序替换
- 进程等待
- 进程程序替换
- 通过进程等待和进程程序替换来理解守护进程
进程等待
僵尸进程的产生原因是:子进程先于父进程退出,在子进程退出时会给父进程发送SIGCHILD信号,而父进程接收到这个信号后选择不处理,从而导致子进程的退出状态信息没有被接收,从而导致子进程成为僵尸进程。
那么正是由于这个原因,我们就需要进行进程等待,来回收子进程的退出状态信息,防止子进程成为僵尸进程。
wait函数就可以实现这个功能
pid_t wait(int* status);
这个函数是一个出参类型的函数,需要我们传入status地址,让wait帮我们将其内部的值进行设置,从而保存退出状态信息
实际上,status只用了后两个字节,也就是低位的两个字节来保存退出状态信息。
这个函数是一个阻塞类型的函数,也就是说,当wait函数没有接收到子进程退出的退出状态信息,那么程序会一直停到这行代码,直到等到接收到了退出状态信息,才会继续向下执行。
使用status得到退出状态信息的方法,按位与。
当子进程正常退出,如果传递了status的地址,会得到子进程的退出码
当子进程非正常退出,如果传递了status的地址,会得到子进程的core dump标志位和退出信号。
注意:coredump标志位表示的是子进程如果异常退出了,coredump值为1,表示产生了核心转储文件,0表示没有产生,是否产生核心转储文件不是单纯取决于进程异常退出,而是取决于。
例如当前的代码,子进程会异常退出,但是没有产生coredump文件。
可以看到coredump值为0,没有产生核心转储文件,使用ulimit -c
查看当前coredump的大小,可以看到大小为0,意味着即使产生了,其大小也为0,所以coredump标志位的值为0。
通过ulimit -c unlimited
将大小设为无限
这样就可以产生核心转储文件了。
除了使用wait函数之外,也可以使用waitpid来进行进程等待
pid_t waitpid(pid_t pid, int* status, int options);
pid | status | options |
---|---|---|
-1:等待任一子进程 | 子进程的退出状态信息 | WNOHANG:设置为非阻塞,子进程未结束返回0,结束范围进程pid |
0:等待指定pid的进程 |
需要注意的是:对于非阻塞类型的函数,需要搭配循环来使用
进程程序替换
对于一个bash进程,我们可以通过命令来运行自己的代码,bash进程是当前运行进程的父进程,通过进程概念的理解,我们自己的进程是拷贝了bash的代码的,那么为什么我们的进程不会运行bash进程呢?
原因就是进行了进程程序替换。
通过exec函数簇进行进程程序替换。
其中包含
//path需要带路径,arg第一个参数为可执行程序本身,多个参数用”,“隔开,结尾用NULL,
//若调用成功,则运行替换后的程序,调用失败返回-1
int execl(const char* path, const char* arg,...);
//与上述相同,path不用带路径
int execlp(const char* file, const char* arg,...);
//与上述相同,但是需要自己组织环境变量
int execle(const char* path, const char* arg,..., char* const envp[]);
//与execl相似,但是传递的命令行参数是以数组指针的方式
int execv(const char* path, char* const argv[]);
//与execlp相似,但是传递的命令行参数是以指针数组的方式
int execvp(const char* fail, char* const argv[]);
//与execlp相似,但是传递的命令行参数是以指针数组的方式
int execve(const char* path, char* const argv[], char<