C语言:如何检测程序自身是否已运行?求跨平台/类Unix实现方法
检测程序自身是否已运行的跨平台/类Unix实现方案
当然有,下面是类Unix系统下的常用实现方法,以及跨平台的通用方案:
类Unix系统专属方法
1. PID文件(最常用)
程序启动时,尝试创建一个包含自身PID的文件(比如/var/run/myapp.pid),核心逻辑如下:
- 检查PID文件是否存在:若存在,读取文件中的PID,通过
kill(pid, 0)系统调用判断该PID对应的进程是否存活(信号0不会终止进程,仅用于检测进程状态)。 - 如果PID无效或对应进程已退出,覆盖PID文件写入当前进程的PID;若进程仍在运行,说明已有实例在运行。
- 为避免多进程竞争创建文件,建议给PID文件加排他锁(用
flock系统调用),进程退出时锁会自动释放,避免残留无效PID文件。
示例C代码片段:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/file.h> #define PID_FILE "/var/run/myapp.pid" int check_single_instance() { int fd = open(PID_FILE, O_RDWR | O_CREAT, 0644); if (fd == -1) { perror("open pid file failed"); return -1; } // 加非阻塞排他锁 if (flock(fd, LOCK_EX | LOCK_NB) == -1) { close(fd); return 1; // 已有实例运行 } // 写入当前PID char pid_buf[20]; snprintf(pid_buf, sizeof(pid_buf), "%d\n", getpid()); ftruncate(fd, 0); write(fd, pid_buf, strlen(pid_buf)); // 保持文件描述符打开,进程退出时锁自动释放 return 0; // 当前是第一个实例 }
2. Unix域套接字(更可靠)
利用Unix域套接字的唯一性:程序启动时尝试绑定一个固定路径的Unix域套接字,如果绑定失败且错误码为EADDRINUSE,说明已有实例在运行。这种方法的优势是,进程退出时套接字会被系统自动清理,不会留下残留文件,比PID文件更可靠。
示例C代码片段:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <sys/un.h> #define SOCKET_PATH "/tmp/myapp.sock" int check_single_instance() { int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket create failed"); return -1; } struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path)-1); // 绑定套接字 if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { if (errno == EADDRINUSE) { close(sockfd); return 1; // 已有实例运行 } else { perror("bind failed"); close(sockfd); return -1; } } // 保持套接字打开,进程退出时自动释放 return 0; // 当前是第一个实例 }
3. 进程名称检查(不推荐)
通过ps命令结合grep过滤进程名称,比如:
ps aux | grep "myapp" | grep -v grep | wc -l
如果结果大于1,说明已有实例。但这种方法容易误判(比如其他进程名称包含myapp),且依赖外部命令,仅适用于简单脚本场景。
跨平台通用方案
如果需要同时支持Windows和类Unix系统,推荐使用成熟的跨平台库:
- Qt的QSingleApplication:Qt框架提供的单实例检测类,只需实例化
QSingleApplication,调用isRunning()即可判断是否已有实例,底层自动适配不同平台的实现。 - Boost.Interprocess:C++跨进程通信库,可通过创建唯一名称的命名互斥量(
named_mutex)实现单实例检测,若创建失败则说明已有实例在运行。
内容的提问来源于stack exchange,提问作者Moiré
相关产品推荐
相关产品推荐

