在 Qt 中实现应用单例运行

在 Qt 中实现应用单例运行(确保同一时间只有一个实例),可以通过以下几种方法实现:

方法 1:使用共享内存(QSharedMemory) - 跨平台

cpp

复制

下载

复制代码
#include <QSharedMemory>
#include <QMessageBox>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    
    // 创建唯一标识的共享内存
    QSharedMemory shared("MyAppSingleInstanceKey");
    if (!shared.create(1)) {  // 尝试创建 1 字节内存
        if (shared.error() == QSharedMemory::AlreadyExists) {
            QMessageBox::warning(nullptr, "警告", "程序已在运行中!");
            return 0;
        }
        // 其他错误处理
        return 1;
    }

    // 主程序逻辑
    MainWindow w;
    w.show();
    
    // 程序退出时自动释放共享内存
    return a.exec();
}

方法 2:使用本地套接字(QLocalServer) - 更可靠(推荐)

cpp

复制

下载

复制代码
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    
    const QString serverName = "MyAppSingleInstanceServer";
    QLocalSocket socket;
    socket.connectToServer(serverName);
    
    // 检查是否已有实例运行
    if (socket.waitForConnected(500)) {
        QMessageBox::warning(nullptr, "警告", "程序已在运行中!");
        
        // 可选:发送消息激活已有实例
        socket.write("ACTIVATE");
        socket.flush();
        socket.close();
        
        return 0;
    }
    
    // 创建本地服务器
    QLocalServer server;
    if (!server.listen(serverName)) {
        QMessageBox::critical(nullptr, "错误", "无法创建单例锁!");
        return 1;
    }
    
    // 主程序逻辑
    MainWindow w;
    QObject::connect(&server, &QLocalServer::newConnection, [&]() {
        QLocalSocket *client = server.nextPendingConnection();
        // 收到激活请求时唤醒窗口
        w.raise();
        w.activateWindow();
        client->deleteLater();
    });
    
    w.show();
    return a.exec();
}

方法 3:使用文件锁(QFile + QLockFile) - 简单轻量

cpp

复制

下载

复制代码
#include <QLockFile>
#include <QDir>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    
    // 创建锁文件(通常放在临时目录)
    QLockFile lockFile(QDir::temp().absoluteFilePath("MyApp.lock"));
    if (!lockFile.tryLock(100)) {
        QMessageBox::warning(nullptr, "警告", "程序已在运行中!");
        return 0;
    }
    
    // 主程序逻辑
    MainWindow w;
    w.show();
    return a.exec();
    // 程序退出时自动释放锁
}

方案对比

方法 优点 缺点 适用场景
共享内存 简单直接 程序崩溃时可能残留锁 简单应用
本地套接字 支持进程间通信,可靠性高 代码稍复杂 需要激活已有实例的场景
文件锁 跨平台,自动清理 依赖文件系统权限 所有平台通用方案

最佳实践建议

  1. 推荐组合使用:本地套接字 + 文件锁

    • QLockFile 确保基础单例

    • QLocalServer 实现激活已有实例功能

  2. 唯一标识注意事项

    • 使用应用专属 ID(如 com.company.appname

    • 避免使用普通用户无权限的路径

  3. 崩溃处理

    • 共享内存方案需处理 QSharedMemory::AlreadyExists 错误

    • 文件锁方案可设置 lockFile.setStaleLockTime(0) 禁用旧锁检测

完整示例(本地套接字方案增强版)

cpp

复制

下载

复制代码
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
#include <QLockFile>
#include <QDir>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 双重检查:文件锁 + 套接字
    QLockFile lockFile(QDir::temp().filePath("MyApp.lock"));
    if (!lockFile.tryLock(100)) {
        // 尝试唤醒已有实例
        QLocalSocket socket;
        socket.connectToServer("MyAppServer");
        if (socket.waitForConnected(500)) {
            socket.write("ACTIVATE");
            socket.waitForBytesWritten();
        }
        return 0;
    }

    // 创建本地服务器
    QLocalServer server;
    if (!server.listen("MyAppServer")) {
        QMessageBox::critical(nullptr, "错误", "无法创建进程锁");
        return 1;
    }

    MainWindow w;
    
    // 处理激活请求
    QObject::connect(&server, &QLocalServer::newConnection, [&]() {
        if (QLocalSocket *socket = server.nextPendingConnection()) {
            socket->waitForReadyRead(100);
            w.showNormal();
            w.raise();
            w.activateWindow();
            socket->deleteLater();
        }
    });

    // 正常启动
    w.show();
    return app.exec();
}

重要提示 :在程序退出时,QLockFileQLocalServer 会自动释放资源。对于共享内存方案,需确保程序正常退出(或添加崩溃处理

相关推荐
hope_wisdom20 天前
Linux系统编程之共享内存
linux·共享内存·linux系统·linux编程
callJJ1 个月前
JAVA网络编程——socket套接字的介绍上(详细)
网络·网络协议·tcp/ip·udp·socket·套接字·网络原理
陈 洪 伟1 个月前
微服务架构中的多进程通信--内存池、共享内存、socket
socket·微服务架构·共享内存·多进程
利刃大大1 个月前
【网络编程】二、UDP网络套接字编程详解
网络·c++·网络协议·udp·socket·套接字
Thanks_ks2 个月前
探秘 Python 网络编程:构建简单聊天服务器
python·网络编程·socket·tcp·客户端·套接字·聊天服务器
阳区欠3 个月前
【Linux】进程通信
linux·运维·服务器·共享内存·进程通信·system v·管道文件
沧海一笑-dj3 个月前
【鸿蒙开发】Hi3861学习笔记- TCP客户端
网络·socket·harmonyos·tcp·tcp客户端·套接字·hi3861
陈 洪 伟3 个月前
CUDA编程(4):共享内存:减少全局内存访问、合并全局内存访问
cuda·共享内存·全局内存
极客代码3 个月前
Linux IPC:System V共享内存汇总整理
linux·c语言·开发语言·并发·共享内存·通信·system v