程序中经常需要有这么一个功能:只允许本程序的单个实例运行,即不能多次运行一个程序。检测某个进程是否在运行,在shell中可以很轻松的用命令ps -A|grep xxx找出来,但对于程序来说,该怎么检测呢?我参考了aecium程序的方法:同样调用ps -A|grep xxx。也许会存在更先进的方法,比如dbus、系统信号量之类的技术,总之这个不会是最好的方法,不过且看看其技巧。
首先要获得当前进程的名字以便传给grep,一般通过main的argv[0]可得到运行时的程序名,不过要注意的是,通过路径运行的程序如./a.out,argv[0]也是./a.out的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> void program_unique_check(const char* program) { FILE *fd; pid_t id = 0; char command[50] = {0}; char pid_num[50] = {0}; const char* program_name; program_name = strrchr (program, '/'); //过滤得到程序的文件名 if (program_name) ++program_name; else program_name = program; //组成执行的命令ps -Ao pid,comm|grep xxx sprintf(command, "ps -Ao pid,comm|grep %s", program_name); printf ("Command to excute: %s\n", command); //以管道方式执行命令 if ( (fd = popen(command, "r")) == NULL ) { perror("popen"); exit(EXIT_FAILURE); } //从管道读回执行结果,这里只为了取得PID,所以只读取前最多20个字符(PID不可能有那么长吧!) fgets(pid_num, 20, fd); printf ("Result :\n%s\n", pid_num); //转换结果字符为整形数值 id = atoi(pid_num); printf ("DETECTED PID: %d\n", id); //判断是否自己 if (getpid() == id) printf ("This's my self: %d\n", id); else { printf ("Here's one already running: %d\nI'll kill him!\n", id); //SIGKILL信号,当然也可以是其他信号的 if ( kill (id, SIGKILL) == -1 ) { perror("kill"); exit(EXIT_FAILURE); } } } int main (int argc, char**argv) { program_unique_check(argv[0]); sleep (10); return 0; } |
本来还考虑,字符串传入atoi()要不要过滤,所以一开始还用了|awk '{print $1}'来给命令结尾,不过发现atoi只读取第一段有效数据来进行转换,就简化这点了。
ZDClient和ZLEVOClient都已经加入了运行实例检测的功能,-l参数可通过信号通知原运行程序离线。

总觉得这个办法不太好.人家把 ZDClient 改个名字运行,就看不出来了...
Link | 五月 26th, 2009 at 15:30
确实~但是不同名字的程序算不算同一个程序呢?哈哈~
一般用户没那么刁难的……
Link | 五月 26th, 2009 at 17:49
哇,可怜才刚在学linux c 紧跟大牛步伐。。
Link | 五月 27th, 2009 at 00:29
http://www.azuresky.net.ru/blog/read.php/14.htm
只让程序执行一个副本,这是APUE的一个例子,你的实现很别扭,看来你没看过APUE,哈哈,要看看了
Link | 五月 28th, 2009 at 17:56
所以我说这不是最好的方法,呵呵.
文件锁信号量锁等方法确实更常用,dhclient、apt都是用了文件锁的方法,而全局信号量锁在win下很常见;
Link | 五月 29th, 2009 at 20:03
Unix单实例后台守护进程的“规范方法” - apt-blog.net IT民工养成计划 PT博客 wrote:
[...] 分类: Unix/Linux 发布于: 2009.06.02 星期二 此前的笔记《Linux程序已运行实体的检测以及其PID的获得》通过Linux里面的bash命令来获取正在运行的同名进程的pid,但实际上,平常此类程序所用的方法都是文件锁,比如dhclient、apt-get系列、pacman诸如此类,都是通过往/var/run里面写入一个包含自身pid的xx.pid文件,同时加上排他锁,只要当前进程还在,新的进程就不可能再加锁,也就能检测出是否单实例了。 [...]
Link | 六月 2nd, 2009 at 20:35