#include <unistd.h>
pid_t setsid(void);
描述:如果调用该系统调用的进程不是其进程组的组长则会创建一个新的会话。调用进程将会称为新会话的组长,会话id和其pid一致。也成为新会话中新的进程组的组长,进程组的id和其pid保持一致。调用进程是新进程组和新会话中唯一的进程,新的会话将会脱离终端的控制。
参数:无
返回值:
成功:调用进程的pid将会返回
失败:-1被返回,errno被设置。
基于上述系统调用,我们可以将一个bash下的子进程变成一个精灵进程,使其不受终端控制。
在终端启动的进程,首先进程继承了终端的会话id和进程组id,其次进程继承了终端的文件描述符(STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO),所以使用setsid()仅能改变进程的会话id和进程组id,却不能删除其继承到的文件描述符。在这种情况下,如果原终端没有关闭,那么进程将会在终端里输出。这种影响需要被避免。所以称为精灵进程还需要对其文件描述符制空。
dup2
验证函数如下:
#include <fcntl.h>
using namespace std;
int main(int argc,char *argv[]){
//用于存放转换成字符串形式的时间格式的缓存区
char timeBuf[128] = {0};
//指定时间
time_t nowTime = time(NULL);
strftime (timeBuf,sizeof(timeBuf),"%Y-%m-%d %H-%M-%S",localtime(&nowTime));
cout << timeBuf << endl;
getchar();
pid_t pid = fork();
if(pid)
exit(0);
setsid();
/*
int fd = open("/dev/null",O_RDWR,0);
if(fd != -1){
dup2(fd,STDIN_FILENO);
dup2(fd,STDOUT_FILENO);
dup2(fd,STDERR_FILENO);
if(fd > STDERR_FILENO)
close(fd);
}
*
*/
sleep(30);
cout << "精灵进程a.out" << endl;
sleep(60);
}
结论描述:
启动进程,观察a.out在进程树的位置,是终端的一个子进程,如下
敲击回车之后,执行了setsid(),手动退出启动进程的终端,观察a.out在进程树的位置,如下