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

Qt实现程序单实例运行(只能运行1个进程)及QSharedMemory用法

1. 问题提出

        在开发时,经常遇到这样的需求或场景:程序只能被启动一次,不能启动多次,启动多次会导致混乱,如:可执行程序用到文件指针、串口句柄等。试想如果存在多个同一个文件的句柄或同一个串口的句柄,就可能在同一时刻对同一文件或串口进行写操作,这样会导致文件内容杂乱、损坏;现实中,当一个串口被一个程序占用时,另外一个程序尝试打开这个串口会报错,因此需要控制程序运行时只能开启一个实例,如何用Qt实现程序单实例运行?

2. 实现方法

         直接上代码,看代码注释就能理解

#include <QSharedMemory>
#include <QDebug>
bool programIsRunning(QSharedMemory**ppSharedMemory)
{/* 为共享内存定义一个字符串类型的key,该key用于标识共享内存对象。* key可以是任意字符串,但必须保证程序运行的机器上不能同时存在同样* 字符串表示的共享内存对象,否则就会造成共享内存访问混乱*/const auto key = QString(QLatin1String("huaHaiFCSoftWare"));bool isRunning = false;auto pSharedMemory = new QSharedMemory(key); // 创建共享内存对象/* 将指向共享内存对象的指针的地址保存到一个二级指针上,* 便于程序退出时,删除该共享内存对象*/ppSharedMemory = &pSharedMemory;// 创建一段大小为1024的共享内存段auto b = pSharedMemory->create(1024);/* 创建共享内存时也许出错了,获取错误码*/auto errNo = pSharedMemory->error();/* 后续代码要读写刚才创建的共享内存中的内容,* 在读写共享内存之前要锁定该段共享内存,防止共享内存的内容被另外的* 进程或本程序的另外一个实例更改,有点类似多线程下访问数据需要加锁*/pSharedMemory->lock();/* 如果上面create创建共享内存成功,那么就向共享内存* 写入一点东西,写入的东西可随意,这里写入的是共享内存对象的标识符*/if(b){auto pSharedMemoryData = static_cast<char*>(pSharedMemory->data()); // 获取共享内存的数据指针strncpy_s(pSharedMemoryData, 1024, key.toStdString().c_str(), strlen(key.toStdString().c_str()) + 1);}/** 如果上面create创建共享内存失败,且失败的原因是该段共享内存存在了,证明* 存在本程序的一个实例已经在运行,该段共享内存就是这个已经在运行的实例创建的*/else if(!b && (QSharedMemory::AlreadyExists == errNo)){/* 以读写模式将事先已经在运行的本程序的实例进程附到这段共享内存上,* 如果不调用attach,则data()函数将返回nullptr*/pSharedMemory->attach();auto pSharedMemoryData = static_cast<char*>(pSharedMemory->data());/*将共享内存的内容读出并检测是否和以前写入*共享内存的内容一样,如果一样,证明本程序的*一个实例已经在运行,则就将正在运行标志isRunning设置为true*/if((nullptr != pSharedMemoryData) && !strcmp(pSharedMemoryData, key.toStdString().c_str())){qDebug() << QStringLiteral("程序已经在运行,\n同一程序不能开启多个!");isRunning = true;}}pSharedMemory->unlock(); // 访问完共享内存后,要解锁,否则其它进程或本程序的其它实例访问不了这段共享内存/* 注意:不能在本函数delete共享内存对象,否则create创建的共享内存的内容会释放,这样会造成本程序的多个实例启动时,会检测不到有本程序的实例已经在运行*///  delete pSharedMemory;return isRunning;
}int main(int argc, char *argv[])
{QApplication a(argc, argv);QSharedMemory**ppSharedMemory = nullptr;// 如果发现本程序的一个实例已经在运行,则本次启动的实例进程直接退出if(programIsRunning(ppSharedMemory)){delete ppSharedMemory;return 1;}// 程序的其它代码略auto nRet = a.exec();// 当程序完全退出时才删除创建的共享内存对象delete ppSharedMemory;return nRet;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Vue】智慧商城
  • 使用Docker辅助图像识别程序开发:在Docker中显示GUI、访问GPU、USB相机以及网络
  • Robust Tiny Object Detection in Aerial Images amidst Label Noise
  • 第53集《摄大乘论》
  • 高中数学:数列-基础概念
  • 【清华大学】《自然语言处理》(刘知远)课程笔记 ——NLP Basics
  • 【计算机毕业设计】283基于微信小程序校园订餐
  • 20.水仙花指数
  • SpringBoot整合钉钉实现消息推送
  • 河海大学上岸经验分享!
  • 数据中心网络架构设计与优化
  • WPF 简单页面切换示例
  • SAP_ABAP_消息类型
  • 【Pytorch】一文向您详细介绍 torch.nn.DataParallel() 的作用和用法
  • Web前端高亮:深度解析高亮技术的四个方面、五个方面、六个方面与七个方面
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • [笔记] php常见简单功能及函数
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【Linux系统编程】快速查找errno错误码信息
  • co模块的前端实现
  • gitlab-ci配置详解(一)
  • Java深入 - 深入理解Java集合
  • Laravel5.4 Queues队列学习
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • MySQL几个简单SQL的优化
  • Python学习笔记 字符串拼接
  • Quartz初级教程
  • Service Worker
  • 缓存与缓冲
  • 前端代码风格自动化系列(二)之Commitlint
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • puppet连载22:define用法
  • ​2020 年大前端技术趋势解读
  • # 数仓建模:如何构建主题宽表模型?
  • $GOPATH/go.mod exists but should not goland
  • (09)Hive——CTE 公共表达式
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (分享)自己整理的一些简单awk实用语句
  • (三分钟)速览传统边缘检测算子
  • (一)、软硬件全开源智能手表,与手机互联,标配多表盘,功能丰富(ZSWatch-Zephyr)
  • (一)SpringBoot3---尚硅谷总结
  • .NET IoC 容器(三)Autofac
  • .NET 给NuGet包添加Readme
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [20150629]简单的加密连接.txt
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [Android] Android ActivityManager
  • [Apio2012]dispatching 左偏树
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步
  • [BZOJ3223]文艺平衡树
  • [BZOJ4010]菜肴制作
  • [C++]指针与结构体
  • [C++初阶]vector的初步理解