【并发程序设计】5.守护进程

5.守护进程

概念:

守护进程又叫精灵进程(Daemon Process),它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

特点:

始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。

它是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭

举例:

http 服务的守护进程叫 httpd,mysql 服务的守护进程叫 mysqld。

相关名词:

  • 进程组(Process Group): 进程集合,每个进程组有一个组长(Leader),其进程 ID 就是该进程组 ID。
  • 会话(Session): 进程组集合,每个会话有一个组长,其进程 ID 就是该会话组 ID。
  • 控制终端(Controlling Terminal):每个会话可以有一个单独的控制终端,与控制终端连接的 Leader 就是控制进程(Controlling Process)。

创建守护进程

新用到的函数有:

  1. setsid 于创建一个新的会话,并将当前进程设置为新会话的组长
  2. getsid 获取当前进程所在会话的会话ID
  3. getpid 获取当前进程的进程ID
  4. getpgid 获取当前进程的进程组ID

setsid 函数

  1. 原型

    #include <unistd.h>
    pid_t setsid(void);
    
  2. 功能:创建一个新的会话,并将当前进程设置为新会话的领导者。

  3. 返回值

    • 成功时返回新的会话ID
    • 失败时返回-1。

getsid 函数

  1. 原型

    #include <unistd.h>
    pid_t getsid(pid_t pid);
    
  2. 功能:获取指定进程所在的会话ID。

  3. 参数pid - 要查询的进程ID。如果传入0,则返回当前进程所在的会话ID。

  4. 返回值

    • 成功时返回指定进程所在的会话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 结束进程: psefgrepa.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调试的进程
  • 22
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值