Linux程序已运行实体的检测以及其PID的获得

五月 25, 2009

程序中经常需要有这么一个功能:只允许本程序的单个实例运行,即不能多次运行一个程序。检测某个进程是否在运行,在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参数可通过信号通知原运行程序离线。

tags: , , ,
posted in Programming, Unix/Linux by PT

Follow comments via the RSS Feed | 留下评论 | Trackback URL

6 Comments to "Linux程序已运行实体的检测以及其PID的获得"

  1. bones7456 wrote:

    总觉得这个办法不太好.人家把 ZDClient 改个名字运行,就看不出来了...

    回复回复
  2. PT wrote:

    确实~但是不同名字的程序算不算同一个程序呢?哈哈~

    一般用户没那么刁难的……

    回复回复
  3. B2Kee wrote:

    哇,可怜才刚在学linux c 紧跟大牛步伐。。

    回复回复
  4. AzureSky wrote:

    http://www.azuresky.net.ru/blog/read.php/14.htm

    只让程序执行一个副本,这是APUE的一个例子,你的实现很别扭,看来你没看过APUE,哈哈,要看看了

    回复回复
  5. PT wrote:

    所以我说这不是最好的方法,呵呵.

    文件锁信号量锁等方法确实更常用,dhclient、apt都是用了文件锁的方法,而全局信号量锁在win下很常见;

    回复回复
  6. 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文件,同时加上排他锁,只要当前进程还在,新的进程就不可能再加锁,也就能检测出是否单实例了。 [...]

Leave Your Comment

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。

Page optimized by WP Minify WordPress Plugin

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org