如何保证只有一个进程实例

简介:
作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
微博:weibo.com/glinuxer
QQ技术群:4367710
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。

============================================================================================================================

在编写服务进程的时候,经常有这样一个需求:保证服务进程只有一个实例在运行。

为实现这个简单的功能,有下面各种常见的实现方式:
1. 通过已知的进程名,来查询是否有同名的进程正在运行。
   可以利用proc,也可以读取ps的输出等;
2. 利用pid文件,这也是linux各种服务常见的实现方式:    
    服务进程启动的时候,首先在指定目录下,一般为/var/run/,查找是否已经存在对应该进程的pid文件。
   如果已经存在,表明有同样的进程在运行。但是也许该进程意外崩溃,所以需要进一步检查。读取该pid文件,获得pid。
   然后再利用确定该pid的进程是否存在。如存在,是否为同名进程。

上面两种方式,是我以前常用的方法。后来,我更倾向于下面这种利用flock文件锁的方式。
闲话不说,见代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>

  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8. #include <sys/file.h>
  9. #include <unistd.h>

  10. #include <my_basetype.h>

  11. static int g_single_proc_inst_lock_fd = -1;

  12. static void single_proc_inst_lockfile_cleanup(void)
  13. {
  14.     if (g_single_proc_inst_lock_fd != -1) {
  15.         close(g_single_proc_inst_lock_fd);
  16.         g_single_proc_inst_lock_fd = -1;
  17.     }
  18. }

  19. B_BOOL is_single_proc_inst_running(const char *process_name)
  20. {
  21.     char lock_file[128];
  22.     snprintf(lock_file, sizeof(lock_file), "/var/tmp/%s.lock", process_name);

  23.     g_single_proc_inst_lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
  24.     if (-1 == g_single_proc_inst_lock_fd) {
  25.         fprintf(stderr, "Fail to open lock file(%s). Error: %s\n",
  26.             lock_file, strerror(errno));
  27.         return B_FALSE;
  28.     }

  29.     if (0 == flock(g_single_proc_inst_lock_fd, LOCK_EX | LOCK_NB)) {
  30.         atexit(single_proc_inst_lockfile_cleanup);
  31.         return B_TRUE;
  32.     }

  33.     close(g_single_proc_inst_lock_fd);
  34.     g_single_proc_inst_lock_fd = -1;
  35.     return B_FALSE;

  36. }
注:这个代码由我自定义的类型,如B_BOOL。感兴趣的同学,可以自行更改。

is_single_proc_inst_running为关键函数,返回true,则表明只有一个进程实例在运行(本进程)。返回false则表明已有同名进程在运行了。

利用非阻塞的文件锁,对相应的文件进行上锁。成功获得文件锁的时候,就排斥了其它实例再次拿锁。在进程退出时,无论是正常退出还是意外崩溃的时候,Linux内核本身都会关闭该文件描述符。
当文件关闭时,文件锁都会被释放。这样新的服务进程可以再次启动。


但是我在写这个代码时,还是利用atexit,实现了对该文件描述符的关闭。即使加了这个不必要的实现,这份代码仍然比最早提出的两种方式要简单的多。
这份代码没有考虑多线程竞争,因为没有必要。一般来说,检测进程唯一实例应该是在进程刚刚启动的时候。那时,应该只有一个线程。


希望大家对这个实现提意见,或者分享你的方法。
目录
相关文章
|
11月前
|
Shell Linux
shell脚本多进程并发写法实例(高阶修炼)
shell脚本多进程并发写法实例(高阶修炼)
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
106 0
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
|
缓存 监控 NoSQL
Python编程:supervisor模块管理进程实例
Python编程:supervisor模块管理进程实例
549 0
Python编程:supervisor模块管理进程实例
|
C++ Windows
windows启动单个进程实例(系统中只有一个运行实例)
windows启动单个进程实例(系统中只有一个运行实例)
185 0
windows启动单个进程实例(系统中只有一个运行实例)
|
Linux
Linux系统查询指定路径下的进程,根据进程id号杀进程方法,进程卡死解决方法实例演示
Linux系统查询指定路径下的进程,根据进程id号杀进程方法,进程卡死解决方法实例演示
201 0
Linux系统查询指定路径下的进程,根据进程id号杀进程方法,进程卡死解决方法实例演示
Mac 技术篇-苹果笔记本休眠启动后WIFI连接转圈卡死置灰不可用解决方法,mac通过终端杀进程实例演示
Mac 技术篇-苹果笔记本休眠启动后WIFI连接转圈卡死置灰不可用解决方法,mac通过终端杀进程实例演示
1148 0
Mac 技术篇-苹果笔记本休眠启动后WIFI连接转圈卡死置灰不可用解决方法,mac通过终端杀进程实例演示
|
Python
Python 技术篇-通过进程名获取进程pid实例演示,使用psutil库获取进程id
Python 技术篇-通过进程名获取进程pid实例演示,使用psutil库获取进程id
424 0
Python 技术篇-通过进程名获取进程pid实例演示,使用psutil库获取进程id
|
SQL 关系型数据库 MySQL
MySQL 数据库sql命令查询被锁的表实例演示,mysql的锁表与解锁,mysql强制解锁杀掉进程,mysql查询锁表一直转圈
MySQL 数据库sql命令查询被锁的表实例演示,mysql的锁表与解锁,mysql强制解锁杀掉进程,mysql查询锁表一直转圈
1467 0
MySQL 数据库sql命令查询被锁的表实例演示,mysql的锁表与解锁,mysql强制解锁杀掉进程,mysql查询锁表一直转圈
|
Windows
Windows 技术篇-cmd强制关闭端口、解除端口占用方法,cmd查询端口相关的进程pid并杀死进程实例演示
Windows 技术篇-cmd强制关闭端口、解除端口占用方法,cmd查询端口相关的进程pid并杀死进程实例演示
690 0
Windows 技术篇-cmd强制关闭端口、解除端口占用方法,cmd查询端口相关的进程pid并杀死进程实例演示
|
Python Linux 测试技术
python多进程通信实例分析
python多进程通信实例分析操作系统会为每一个创建的进程分配一个独立的地址空间,不同进程的地址空间是完全隔离的,因此如果不加其他的措施,他们完全感觉不到彼此的存在。那么进程之间怎么进行通信?他们之间的关联是怎样的?实现原理是什么?本文就来借助Python简单的聊一下进程之间的通信?还是那句话,原理是相同的,希望能透过具体的例子来体会一下本质的东西。
3016 0

相关实验场景

更多