关于return 0和exit(0)
return 0
的行为
- 作用范围:
return 0
只能在main
函数中使用,用于结束main
函数并返回一个退出状态码给操作系统。 - 退出状态:返回值
0
通常表示程序成功执行,非0
的值则表示程序遇到错误或异常情况。 - 清理行为:当
return
被执行时,它会先执行main
函数内部的所有局部变量的析构函数。它还会执行任何自动清理的操作,如关闭局部打开的文件,但不会强制执行全局的清理(如全局对象的析构)。
exit(0)
的行为
- 作用范围:
exit(0)
可以在程序的任何地方调用,包括main
函数之外的函数。这使得它非常适合在需要立即终止程序时使用,比如在错误处理代码中。 - 退出状态:
0
仍然表示成功,但它可以用其他值(如1
、-1
)来表示不同的错误状态。 - 清理行为:
exit
会立即终止程序,并进行以下清理操作:- 调用所有已注册的
atexit
函数(用于注册程序退出时需要执行的自定义函数)。 - 调用全局对象的析构函数。
- 刷新所有输出流,确保输出数据被正确写入。
- 关闭所有打开的文件描述符。
- 调用所有已注册的
父进程退出,让程序运行在后台
// 生成子进程,父进程退出,让程序运行在后台,由系统1号进程托管,不受shell的控制。
if (fork()!=0) exit(0);
fork返回值有两个,两次返回的区别是子进程的返回值是0,而父进程的返回值则是子进程的进程ID。
如果 fork()
返回的值不为0,则当前进程是父进程,它会调用 exit(0)
退出。这意味着父进程退出,子进程继续运行。这使得程序在后台运行,并且不受 shell 的控制,系统的第1号进程(init)将成为它的父进程。
程序在后台运行通常是指它不依赖于用户的终端输入,也不会干扰用户的终端输出。父进程退出而子进程继续运行的机制实现了这种“后台”运行的特性。
恢复 SIGCHLD 信号的默认处理:
signal(SIGCHLD,SIG_DFL);
signal(SIGCHLD,SIG_DFL);
恢复了SIGCHLD
信号的默认处理方式。这个信号在子进程终止时会发送给父进程,默认处理方式会让父进程调用wait()
函数以回收子进程的资源。
execl函数和execv函数
while (true)
{
if (fork()==0)
{
execv(argv[2],pargv);
exit(0); // 如果被调度的程序运行失败,才会执行这行代码。
}
else
{
wait(nullptr); // wait()函数会阻塞,直到被调度的程序终止。
sleep(atoi(argv[1])); // 休眠timetvl秒,然后回到循环。
}
}
- 如果
execv()
执行失败(通常不会发生),子进程会执行exit(0)
退出。 - 如果是父进程(
fork()
返回非0),则父进程会等待子进程的结束(即被调度的程序终止),然后sleep(atoi(argv[1]))
休眠timetvl
秒,再次回到循环,重新创建子进程并执行指定程序。
int execl(const char *path, const char *arg, ...);
path
:要执行的程序的路径。- 第二个参数通常也为程序名,和第一个参数一样,剩下参数填操作
- 必须以NULL结尾。
int execv(const char *path, char *const argv[]);
execv函数是把execl函数后面的参数全部存在argv数组中,