跳转至

进程单例

以下是一篇跨平台进程单实例技术调研及实现方案,包含Windows/Linux/macOS三平台兼容的C++代码实现:

跨平台进程单实例技术实现

一、技术背景

  • 进程单实例控制是保证关键服务唯一性的核心技术,常见于系统守护进程、桌面应用程序等场景。本文通过三种系统级机制实现跨平台支持:

  • Windows:内核对象互斥体

  • Linux/macOS:文件锁机制
  • 通用方案:跨进程内存共享

二、实现方案

方案一:跨平台文件锁(推荐)

#include <iostream>
#include <string>
#include <cstdlib>

#if defined(_WIN32)
#include <Windows.h>
#else
#include <sys/file.h>
#include <unistd.h>
#include <fcntl.h>
#endif

class SingleInstance {
public:
    SingleInstance(const std::string& lockName) {
#if defined(_WIN32)
        // Windows命名互斥体
        hMutex = CreateMutexA(NULL, TRUE, lockName.c_str());
        isRunning = (GetLastError() == ERROR_ALREADY_EXISTS);
#else
        // Unix系文件锁
        std::string lockPath = "/tmp/" + lockName + ".lock";
        fd = open(lockPath.c_str(), O_CREAT | O_RDWR, 0666);
        isRunning = (flock(fd, LOCK_EX | LOCK_NB) != 0);
#endif
    }

    ~SingleInstance() {
#if defined(_WIN32)
        if(hMutex) {
            ReleaseMutex(hMutex);
            CloseHandle(hMutex);
        }
#else
        if(fd >= 0) {
            flock(fd, LOCK_UN);
            close(fd);
        }
#endif
    }

    bool isAnotherRunning() const { return isRunning; }

private:
#if defined(_WIN32)
    HANDLE hMutex = NULL;
#else
    int fd = -1;
#endif
    bool isRunning = false;
};

// 使用示例
int main() {
    SingleInstance si("my_app");
    if(si.isAnotherRunning())  {
        std::cerr << "Application already running!" << std::endl;
        return EXIT_FAILURE;
    }

    // 主程序逻辑
    std::cout << "Application started successfully" << std::endl;
    std::cin.get(); 
    return EXIT_SUCCESS;
}

方案二:共享内存检测

// Windows实现
#ifdef _WIN32
#include <windows.h>

class WinSharedMem {
public:
    WinSharedMem(const char* name) {
        hMapFile = CreateFileMappingA(
            INVALID_HANDLE_VALUE, NULL, 
            PAGE_READWRITE, 0, 256, name);
        exists = (GetLastError() == ERROR_ALREADY_EXISTS);
    }
    // ... 其他成员函数
};
#endif

// Linux/macOS实现
#if defined(__linux__) || defined(__APPLE__)
#include <sys/mman.h>
#include <fcntl.h>

class UnixSharedMem {
public:
    UnixSharedMem(const char* name) {
        fd = shm_open(name, O_CREAT | O_RDWR, 0666);
        exists = (errno == EEXIST);
    }
    // ... 其他成员函数
};
#endif

三、关键实现点

  • Windows核心机制 使用CreateMutexA创建命名互斥体 通过GetLastError()检测ERROR_ALREADY_EXISTS 需显式释放互斥体资源
  • Linux/macOS实现 采用flock()文件锁实现进程排他 锁文件存储在/tmp目录保证可写性 文件描述符自动回收机制
  • 跨平台封装 使用预处理器指令区分平台 统一接口isAnotherRunning() RAII模式管理资源生命周期

四、测试验证

Linux/macOS编译

g++ -std=c++11 singleton.cpp  -o singleton

Windows编译(VS开发者命令提示)

cl /EHsc singleton.cpp 

五、方案对比

特性 文件锁方案 共享内存方案
跨平台性 优秀 需平台特定实现
可靠性 高(内核级锁) 中等
资源消耗 较高
实现复杂度 简单 复杂

完整代码库可参考的实现模式,建议优先采用文件锁方案作为基础实现。实际部署时需注意权限管理(如Linux下的/tmp目录权限)和异常处理(如进程崩溃后的锁释放机制)。

完整代码

Github