111-单例守护进程

有同学会很好奇,为什么这里又来一次守护进程,之前进程间关系不是已经说过一次了吗?

没错,之前的确是讲过,不过那时候我们只是讲了守护进程的原理,实现方法,然而这一次并不是讲守护进程怎么实现。

1. 问题提出

实际上之前我们写的守护进程,如果多次启动,就会产生多个相同的进程。比如下面这样:


这里写图片描述
图1 启动几次就有几个实例

进程 processd 就是一个守护进程,每次启动都会产生一个实例,实际上很多时候守护进程都是服务进程,我们并不希望系统中存在多份实例。如果同时运行多个实例,每个实例都会进行相同的操作,造成错误。比如系统中的 cron 守护进程,这是一个定时任务程序,如果存在多个 cron 进程,那就糟糕了。

2. 单例守护进程

如果一个程序被启动多次,系统中仍然只存在一份实例,这种进程就是单例进程。放到守护进程上来说,就是单例守护进程。

一般来说,就算你多次启动它也没关系,它内部提供了检测机制,对进程进行了保护。接下来要讲的就是这种机制是如何实现的。

3. 实现单例守护进程

它采用的技术就是之前我们学习的记录锁。只要点破这层纸,我相信很多同学已经知道怎么写程序了。

其原理很简单,启动进程的时候,对约定的文件进行加锁,如果加锁失败,说明已经有进程对其加过锁了,直接退出。

4. 程序清单

singleprocessd 演示了如何实现一个单例守护进程。

4.1 代码

// singleprocessd.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

// 对文件加锁
int lockfile(int fd) {
  struct flock flk;

  flk.l_type = F_WRLCK;
  flk.l_start = 0;
  flk.l_whence = SEEK_SET;
  flk.l_len = 0;
  // 非阻塞方式加锁
  return fcntl(fd, F_SETLK, &flk);
}

int already_running(void) {
  int fd; 
  char buf[16];

  // 输出日志文件
  FILE* fp = fopen("/tmp/singleprocess.log", "a");
  // 锁文件
  fd = open("/var/run/singleprocess.pid", O_RDWR | O_CREAT, 0644);
  if (fd < 0) {
    fprintf(fp, "can't open /var/run/singleprocess.pid: %s\n", strerror(errno));
    fclose(fp);
    exit(1);
  }

  if (lockfile(fd) < 0) {
    if (errno == EACCES || errno == EAGAIN) {
      fprintf(fp, "singleprocess already running: %s\n", strerror(errno));
      close(fd);
      fclose(fp);
      return 1;// 表示已被加锁
    }   
    fprintf(fp, "can't lock /var/run/singleprocess.pid: %s\n", strerror(errno));
    fclose(fp);
    exit(1);
  }

  ftruncate(fd, 0);// 截断成 0
  sprintf(buf, "%d", getpid());
  write(fd, buf, strlen(buf) + 1); 
  return 0; // 加锁成功
}

int main() {
  if (daemon(0, 0) < 0) {
    perror("daemon");
    return 1;
  }
  if (already_running()) {
    return 1;
  }

  while(1) {
    sleep(10);
    // do something
  }
  return 0;
}

4.2 编译和运行

  • 编译
gcc singleprocessd.c -o singleprocessd
  • 运行

运行的时候用 root 权限,因为它要向 /var/run 下面写文件


这里写图片描述
图2 单例守护进程

如图 2 所示,singleprocessd 程序启动了 4 次,但是最终只有一个实例在运行。日志 /tmp/singprocess.log 中记录了后三次运行历史。

锁文件 /var/run/singprocess.pid 中保存的是实例的 pid,和 ps 命令中查看的结果是一致的。

5. 总结

  • 理解什么是单例守护进程
  • 为什么要采用单例守护进程
  • 利用记录锁实现单例守护进程
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值