- pid_t fork(void);//pid_t为int类型,进行了宏定义
- pid_t getpid();// 获取当前进程的 pid 值。
- pid_t getppid(); //获取当前进程的父进程 pid 值。
因此我们可以通过fork返回的值来判断当前进程是子进程还是父进程。(注: fork 调用生成的新进程与其父进程谁先执行不一定,哪个进程先执行要看系统的进程调度策略)
举个例子来解释fpid的值为什么在父子进程中不同:“相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0。所以返回值为0。
关于fork函数的具体执行和更详细的了解可参考以下:
https://blog.csdn.net/cckluv/article/details/109169941
设置守护进程
可参考链接:https://blog.csdn.net/JMW1407/article/details/108412836
定义
●守护进程是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或循环等待处理某些事件的发生;它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。
●守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机才随之一起停止运行;
●守护进程一般都以root用户权限运行,因为要使用某些特殊的端口(1-1024)或者资源;
●守护进程的父进程一般都是init进程,因为它真正的父进程在fork出守护进程后就直接退出了,所以守护进程都是孤儿进程,由init接管;
●守护进程是非交互式程序,没有控制终端,所以任何输出,无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。
●守护进程的名称通常以d结尾,比如sshd、xinetd、crond等
代码
void create_daemon() //创建守护进程
{
int pid;
if (pid = fork())
exit(0);//是父进程,结束父进程
else if (pid< 0)
exit(1);//fork失败,退出
//已经是第一子进程,脱离终端在后台继续执行
setsid();//设置第一子进程成为新的会话组长和进程组长
//并与控制终端分离
if (pid = fork())
exit(0);//返回新子进程的父进程,即上面的第一子进程,结束第一子进程
else if (pid< 0)
exit(1);//fork失败,退出
//以上执行完毕未推出,则此时正在执行的是第二子进程
//第二子进程不再是会话组长
chdir("/");//改变工作目录到/
umask(0); //重设文件创建掩模
return;
}
因为在代码中把printf及其他不必要的输出已经删掉,读取文件、写入日志等文件描述符还需要使用,所以把关闭文件描述符的系列代码删除了。
僵尸进程和孤儿进程
可参考链接:https://blog.csdn.net/a13568hki/article/details/103851388
一般进程
正常情况下:子进程由父进程创建,子进程再创建新的进程。父子进程是一个异步过程,父进程永远无法预测子进程的结束,所以,当子进程结束后,它的父进程会调用wait()或waitpid()取得子进程的终止状态,回收掉子进程的资源。
2)孤儿进程
孤儿进程:父进程结束了,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程(father died)。子进程的资源由init进程(进程号PID = 1)回收。
3)僵尸进程
僵尸进程:子进程退出了,但是父进程没有用wait或waitpid去获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵死进程。