You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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é

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 07:24:18