【Qt专栏】实现单例程序,禁止程序多开的几种方式

news/2024/7/23 21:27:34 标签: qt, php, 数据库

目录

一,简要介绍

二,实现示例(Windows)

1.使用系统级别的互斥机制

2.通过共享内存(进程间通信-IPC)

3.使用命名互斥锁(不推荐)

4.使用文件锁

5.通过网络端口检测


一,简要介绍

前言

  • 禁止程序多开,也称为“单实例应用程序”或“单例应用程序”,是指通过各种手段防止同一个应用程序同时运行多个实例。这种方法可以提升应用程序的稳定性、资源利用效率和用户体验。

目的

  • 禁止程序多开的主要目的是确保应用程序在同一时刻只能运行一个实例,防止资源浪费、数据冲突、混淆等问题,以提高应用程序的质量和用户满意度。

好处

  1. 资源管理:多个实例同时运行可能导致资源的浪费,如内存、CPU 使用率等。通过限制只能运行一个实例,可以更有效地管理系统资源。
  2. 数据一致性:如果应用程序涉及到对共享数据或状态的修改,多个实例同时运行可能会导致数据不一致的问题。通过禁止多开,可以避免这种情况。
  3. 减少冲突:多个实例可能尝试访问同一资源,如文件、数据库等,导致冲突和错误。禁止多开可以减少这种情况的发生。
  4. 避免混淆:如果应用程序依赖于特定的硬件或外部设备,多个实例可能会导致设备混淆或竞争,从而影响功能正常运行。
  5. 提升用户体验:当用户只期望运行一个实例时,多开可能会让用户感到困惑。通过禁止多开,可以提升用户的体验和易用性。

实现方式

  1. 系统级别互斥机制:使用操作系统提供的互斥机制,如命名互斥体等。
  2. 共享内存或命名管道:使用共享内存或命名管道在不同实例间进行通信,防止多开。
  3. 命名互斥锁或文件锁:创建一个唯一名称的互斥锁或文件锁,如果已经存在,表示已有实例运行。
  4. 网络端口检测:尝试绑定到一个特定的网络端口,如果绑定成功,则表示没有其他实例在运行。
  5. 环境变量检测:检查环境变量,如已设置则表示已有实例运行。

总结

  • 总之,禁止程序多开是一种优化应用程序的方法,可以确保应用程序在不同环境中稳定、高效地运行。选择适合的实现方式取决于应用程序的需求和技术栈。

二,实现示例(Windows)

1.使用系统级别的互斥机制

  • 某些操作系统提供了系统级别的互斥机制,可以防止同一应用程序的多个实例运行。例如,Windows 提供了命名互斥体来实现这一点。
  • 示例模板​​​​​​​​​​​​​​
  • 示例代码
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <Windows.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // L"字符串":表示将ANSI字符串转换成unicode的字符串,使每个字符占两个字节
    HANDLE hMutex = CreateMutex(nullptr, TRUE, (LPCWSTR)qApp->applicationName().toStdWString().c_str());
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        QMessageBox::warning(nullptr, "Error", "An instance of the application is already running.");
        CloseHandle(hMutex);
        hMutex = NULL;
        return 1;
    }

    // 在此处写你的应用程序逻辑代码
    MainWindow w;
    w.show();
    a.exec();

    // 完成后关闭互斥锁
    CloseHandle(hMutex);
    hMutex = NULL;
    return 0;
}

2.通过共享内存(进程间通信-IPC)

  • 使用进程间通信技术,例如共享内存,来检测是否已经有一个实例在运行。
  • 示例模板(使用 Qt 的 QSharedMemory 进行进程间通信)​​​​​​​
  • 示例代码
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QSharedMemory>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSharedMemory sharedMemory(qApp->applicationName());    // 设置绑定的共享内存段的key值
    if(sharedMemory.attach()){
        QMessageBox::warning(nullptr, "Error", "An instance of the application is already running.");
        return 1;
    }else{
        sharedMemory.create(1); // 创建1byte大小的共享内存段
    }

    // 在此处写你的应用程序逻辑代码
    MainWindow w;
    w.show();
    a.exec();

    // 完成后分离共享内存
    sharedMemory.detach();
    return 0;
}

3.使用命名互斥锁(不推荐)

  • 在应用程序启动时创建一个命名互斥锁,确保只有一个实例可以获取锁,其他实例将被阻止。
  • 示例模板
  • 示例代码
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QSystemSemaphore>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 声明一个命名互斥锁,用于防止多开
    QSystemSemaphore semaphore(qApp->applicationName(), 1, QSystemSemaphore::Open);

    if (!semaphore.acquire()) {
        QMessageBox::warning(nullptr, "Error", "An instance of the application is already running.");
        return 1;
    }

    // 在此处写你的应用程序逻辑代码
    MainWindow w;
    w.show();
    a.exec();

    // 释放互斥锁,允许其他实例运行
    semaphore.release();
    return 0;
}

4.使用文件锁

  • 在应用程序启动时创建一个特定的文件锁,如果锁已存在,则表示已经有一个实例在运行。
  • 示例模板​​​​​​​
  • 示例代码
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QFile>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QFile lockFile(qAppName() +".lock");
    if (lockFile.exists()) {
        QMessageBox::warning(nullptr, "Error", "An instance of the application is already running.");
        return 1;
    }

    lockFile.open(QIODevice::WriteOnly);
    lockFile.write("Running"); // 向锁文件写入一些数据
    lockFile.close();

    // 在此处写你的应用程序逻辑代码
    MainWindow w;
    w.show();
    a.exec();

    // 完成后删除锁定文件
    lockFile.remove();
    return 0;
}

5.通过网络端口检测

  • 在应用程序启动时尝试绑定到一个特定的网络端口,如果绑定成功,则表示没有其他实例正在运行。
  • 示例模板
  • 示例代码
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QTcpServer>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTcpServer tcpServer;
    if (!tcpServer.listen(QHostAddress::LocalHost, 12345)) {
        QMessageBox::warning(nullptr, "Error", "An instance of the application is already running.");
        return 1;
    }

    // 在此处写你的应用程序逻辑代码
    MainWindow w;
    w.show();
    a.exec();

    // 完成后关闭服务器
    tcpServer.close();
    return 0;
}


http://www.niftyadmin.cn/n/4970677.html

相关文章

2023科隆游戏展开幕~黑神话等多款国产游戏亮相

这是【游戏开发那些事】第62篇原创 科隆游戏展&#xff0c;全名科隆国际游戏娱乐展览会&#xff08;Gamescom&#xff09;&#xff0c;是世界上最大的电子游戏展览之一。由德国联邦协会互动娱乐软件&#xff08;BIU&#xff09;主办&#xff0c;每年在德国科隆举行&#xff0c;…

uniapp中引入axios的错误?

场景 在unaipp中使用axios npm i axios 下载完成后 然后在页面中使用 axios.get(“http://3000/searchS”) 然后报错 Adapter http’ is not available in the build 原因 在 UniApp 中使用 Axios 发送 HTTP 请求时&#xff0c;如果出现错误 “Adapter http’ is not available…

dockerfile部署前端vue打包的dist文件实战

背景&#xff1a;一般前端开发后会将打包后的dist文件交由我们部署&#xff0c;部署的方式有很多&#xff0c;这里提供一种思路 在服务器的路径下新建一个目录&#xff0c;在目录中新建Dockerfile&#xff0c;编辑这个文件 FROM nginxCOPY ./dist /home/front COPY nginx.con…

Android开发之性能优化工具Profiler

前言 性能优化问题&#xff0c;在我们开发时都会遇到&#xff0c;但是在小厂和对自己要求不严格的情况下&#xff0c;我都很少去做性能优化&#xff1b; 在性能优化上&#xff0c;基本大家都是通过自己的开发经验和性能分析工具来发现问题&#xff0c;今天给大家分享一下小编最…

YOLOv5屏蔽区域检测(选择区域检测)

YOLOv5屏蔽区域检测以及选择区域检测 前期准备labelme选择mask区域 代码改动 前期准备 思路就是通过一个mask掩膜&#xff0c;对我们想要屏蔽或者选择的区域进行遮挡处理&#xff0c;在推理的时候&#xff0c;将有mask掩膜的图像输入&#xff0c;将最后的结果显示在原始图像上…

Flink流批一体计算(18):PyFlink DataStream API之计算和Sink

目录 1. 在上节数据流上执行转换操作&#xff0c;或者使用 sink 将数据写入外部系统。 2. File Sink File Sink Format Types Row-encoded Formats Bulk-encoded Formats 桶分配 滚动策略 3. 如何输出结果 Print 集合数据到客户端&#xff0c;execute_and_collect…

微客云直充卡券优惠话费充值接口开发稳定高效

微客云直充卡券话费 开发团队致力于此模块生命力至少3-5年 此模块以资源种类&#xff0c;官方直联接口为优势&#xff0c;不纯以软件更新为主&#xff0c;力争版本精准化服务用户 单独直充卡券话费系统&#xff0c;直接完成对各种消费场景的流量变现&#xff0c;更加开放与链路…

网络安全(黑客)零基础自学

网络安全是什么&#xff1f; 网络安全&#xff0c;顾名思义&#xff0c;网络上的信息安全。 随着信息技术的飞速发展和网络边界的逐渐模糊&#xff0c;关键信息基础设施、重要数据和个人隐私都面临新的威胁和风险。 网络安全工程师要做的&#xff0c;就是保护网络上的信息安…