5.守护进程
概念:
守护进程又叫精灵进程(Daemon Process),它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
特点:
始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。
它是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭
举例:
http 服务的守护进程叫 httpd,mysql 服务的守护进程叫 mysqld。
相关名词:
- 进程组(Process Group): 进程集合,每个进程组有一个组长(Leader),其进程 ID 就是该进程组 ID。
- 会话(Session): 进程组集合,每个会话有一个组长,其进程 ID 就是该会话组 ID。
- 控制终端(Controlling Terminal):每个会话可以有一个单独的控制终端,与控制终端连接的 Leader 就是控制进程(Controlling Process)。
创建守护进程
新用到的函数有:
setsid
于创建一个新的会话,并将当前进程设置为新会话的组长getsid
获取当前进程所在会话的会话IDgetpid
获取当前进程的进程IDgetpgid
获取当前进程的进程组ID
setsid 函数
原型:
#include <unistd.h> pid_t setsid(void);
功能:创建一个新的会话,并将当前进程设置为新会话的领导者。
返回值:
- 成功时返回新的会话ID
- 失败时返回-1。
getsid 函数
原型:
#include <unistd.h> pid_t getsid(pid_t pid);
功能:获取指定进程所在的会话ID。
参数:
pid
- 要查询的进程ID。如果传入0,则返回当前进程所在的会话ID。返回值:
- 成功时返回指定进程所在的会话ID
- 失败时返回-1。
getpid 函数
pid_t getpid(void);
获取进程id
getpgid 函数
pid_t getpgid(pid_t pid);
获取进程组id
组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。
创建步骤
1.创建子进程,父进程退出
创建子进程然后结束父进程,子进程变成孤儿进程,被init进程收养,子进程在后台运行
if (fork() > 0) { exit(0); }
查看进程: p s − e f ∣ g r e p a . o u t 结束进程: ps -ef|grep a.out 结束进程: ps−ef∣grepa.out结束进程:kill -9 [进程号]
更简便的创建后台进程(不建议使用)
通过这条命令运行代码:$ nohub ./a.out &
进程进入后台运行
2.子进程创建新会话
if (setsid() < 0) { exit(-1); }
子进程成为新的会话组长
子进程脱离原先的终端
4.更改当前工作目录
chdir(“/”);//更改当前工作目录到根目录
守护进程一直在后台运行,其工作目录不能被卸载
重新设定当前工作目录cwd
5.重设文件权限掩码
if (umask(0) < 0) { exit(-1); }
文件权限掩码设置为0
只影响当前进程
6.关闭打开的文件描述符
close(0); close(1); close(2);
关闭所有从父进程继承的打开文件
已脱离终端,stdin / stdout / stderr无法再使用
7.守护进程创建完成
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(int argc, const char *argv[])
{
pid_t pid;
pid = fork();
if(pid<0)
{
perror("fork");
return 0;
}
//1.结束父进程
else if(pid>0)
{
exit(0);
}
printf("Deamon\n");
printf("sid=%d,pid=%d,pgid=%d\n",
getsid(getpid()),
getpid(),
getpgid(getpid()));
//2.子进程创建新会话
if(setsid()<0)
{
perror("setsid");
exit(0);
}
printf("after sid=%d,pid=%d,pgid=%d\n",
getsid(getpid()),
getpid(),
getpgid(getpid()));
//3.更改当前工作目录到根目录
chdir("/");
//4.文件权限掩码设置为0
if(umask(0)<0)
{
perror("unmask");
exit(0);
}
//5.关闭打开的文件描述符
close(0);
close(1);
close(2);
printf("after close \n");
sleep(100);
return 0;
}
GDB调试多进程程序
gcc编译.c程序时加入 -g 参数
gcc -g xxx.c gdb a.out #进入调试
出现上图表示进入了gdb调试
gdb相关命令
run
全速运行star
单步调试n
下一步set follow-fork-mode child/parent
设置GDB只跟踪 子/父 进程代码set setach-on-fork on/off
设置GDB跟踪调试单个进程或多个(默认为on)
on
: 只调试父进程或子进程的其中一个,(根据follow-fork-mode
来决定),这是默认的模式off
:父子进程都在gdb的控制之下,其中一个进程正常调试(根据follow-fork-mode
来决定),另一个进程会被设置为暂停状态。info inferiors
显示GDB调试的进程inferiors [进程序号] (1,2,3....)
切换GDB调试的进程