概念
进程组
一个进程组有多个进程
进程组PID为第一个进程PID,称为组长进程
会话
一个会话有多个进程组
一个会话可以有一个控制终端
建立与控制终端链接的进程称为控制进程(会长进程)进程ID 进程组ID 会话ID 都一样的
谁控制终端谁就是前端进程组,否则就是后端进程组
创建会话
调用进程不能是进程组的组长,该进程变成新会话的首进程(会长进程),原因很简单该进程的PPID和它的子进程PID一样(会话是一个新的组),当然如果调用的也会出错
该进程称为组长,也称为会长
需要root权限(Ubuntu不需要比较宽松)
新会话丢弃原控制终端,该会话没有控制终端
新建会话时,先调用fork,父进程终止,子进程调用setsid()
守护进程
守护进程也叫精灵进程(daemon),是后台服务进程,通常独立于控制终端并且周期性的执行某种任务或等待处理事件发生.一般用d标识(例如sshd)
服务器实际上就做这些事情,周期性的等待数据,读取数据发送数据,(不受用户登入注销影响)
创建守护进程
一 创建子进程,父进程退出
二 子进程中创建setsid()新会话(子进程独立)
三 chdir(文件路径)改变当前目录为家目录,(防止占用可卸载的文件系统)(例如程序在U盘上,运行之后把U盘拔除)
四 (umask())重新设置文件掩码(可以提高守护进程的灵活性)(操作系统默认新创建的文件没有执行权限)
五 关闭文件描述符或将文件描述符重定向(有些打开文件不会使用,无法卸载浪费系统资源)
六 守护进程逻辑
案例创建会话
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid > 0)
{
// 新建会话时父进程先终止
return 0;
}
if (pid == 0)
{
cout << "子进程ID " << getpid() << endl;
// 传0表示当前进程
cout << "子进程组ID " << getpgid(0) << endl;
cout << "子进程会话ID " << getsid(0) << endl;
cout << "-----------------------------" << endl;
// 创建会话
pid_t pid_sid = setsid();
cout << "子进程ID " << getpid() << endl;
// 传0表示当前进程
cout << "子进程组ID " << getpgid(0) << endl;
cout << "子进程会话ID " << getsid(0) << endl;
}
return 0;
}
tty 文字终端
pts 虚拟终端
? 无终端
没有终端的进程在后台运行,不能和用户进行交互
案例守护进程
#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
int main(int argc,char** argv)
{
pid_t pid_fork = fork();
if(pid_fork == -1)
{
perror("pid_t pid_fork = fork();");
exit(1);
}
if(pid_fork > 0)
{
// 父进程退出
exit(0);
}
// 子进程创建会话
pid_t pid_sid = setsid();
if(pid_sid == -1)
{
perror("pid_t pid_sid = setsid();");
exit(1);
}
// 改变程序运行工作目录 只要是不会改变一直存在的目录就可以
chdir("/");
// 改变文件掩码 系统默认文件是不配有执行权限的 所以直接创建出来的文件权限是0666
// umask取反在想与 才会是最终权限
umask(0000);
// 关闭文件描述符
//close(STDIN_FILENO);
//close(STDOUT_FILENO);
//close(STDERR_FILENO);
// 文件重定向
int fd = open("/dev/zero", O_RDONLY); // 这个文件读不完
if(fd == -1)
{
perror("fd open");
exit(1);
}
int fd2 = open("/dev/null",O_RDWR); // 这个文件写不满
if(fd2 == -1)
{
perror("fd2 open");
exit(1);
}
dup2(fd,STDIN_FILENO);
dup2(fd2,STDOUT_FILENO);
dup2(fd2,STDERR_FILENO);
while (true)
{
// 守护进程要做的事
}
return 0;
}