程序中经常需要有这么一个功能:只允许本程序的单个实例运行,即不能多次运行一个程序。检测某个进程是否在运行,在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 改个名字运行,就看不出来了...
确实~但是不同名字的程序算不算同一个程序呢?哈哈~
一般用户没那么刁难的……
哇,可怜才刚在学linux c 紧跟大牛步伐。。
http://www.azuresky.net.ru/blog/read.php/14.htm
只让程序执行一个副本,这是APUE的一个例子,你的实现很别扭,看来你没看过APUE,哈哈,要看看了
所以我说这不是最好的方法,呵呵.
文件锁信号量锁等方法确实更常用,dhclient、apt都是用了文件锁的方法,而全局信号量锁在win下很常见;
Pingback: Unix单实例后台守护进程的“规范方法” - apt-blog.net IT民工养成计划 PT博客