当前位置: 首页 > news >正文

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

目录

一,简要介绍

二,实现示例(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.lryc.cn/news/145491.html

相关文章:

  • 力扣26. 删除有序数组中的重复项
  • 【机器学习】鸢尾花分类-逻辑回归示例
  • Flink CDC介绍
  • Java集合sort排序报错UnsupportedOperationException处理
  • 安防监控/磁盘阵列存储/视频汇聚平台EasyCVR调用rtsp地址返回的IP不正确是什么原因?
  • Spring boot开启定时任务
  • package.json相关知识记录
  • VueRouter使用详解(5000字通关大全)
  • vue axios实现下载文件及responseType:blob注意事项
  • StringBuilder类分享(1)
  • Qt 打开文件列表选择文件,实现拖拽方式打开文件
  • [C/C++]天天酷跑游戏超详细教程-上篇
  • 5G NR:RACH流程 -- Msg1之选择正确的PRACH时频资源
  • 在vue3项目中编辑的时候,解决对话框里边的数据和列表中的数据联动了。深复制
  • 循环结构(个人学习笔记黑马学习)
  • ceph中PGLog处理流程
  • macOS使用命令行连接Oracle(SQL*Plus)
  • Mac下使用Homebrew安装MySQL5.7
  • centos安装Nginx配置Nginx
  • Linux环境下搭建使用缓存中间件Redis
  • Oracle 本地客户端连接远程 Oracle 服务端并使用 c# 连接测试
  • java中上传文件先下载到本地再上传还有就是直接通过文件流url地址进行上传优缺点?
  • 华为复合vlan(mux vlan)
  • 第62步 深度学习图像识别:多分类建模(Pytorch)
  • GPT带我学-设计模式-适配器模式
  • Pyecharts教程(七):使用pyecharts创建堆叠柱状图的示例
  • C++中的强制转换的常用类型及应用场景详解
  • ubuntu调整时区
  • mybatis:动态sql【2】+转义符+缓存
  • 2021年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试