【米尔-MYD-LR3568-GK开发板--试用评测】20——单实例程序
本帖最后由 stm1024 于 2024-12-2 22:09 编辑单实例程序是一种设计模式,用于确保一个应用程序或服务的只有一个实例在运行。常见于桌面应用程序中,尤其是在需要确保不重复打开多个窗口或会话的情况下,例如有独占硬件资源的程序,再打开一个程序已经毫无意义,只会浪费系统资源和报错;或者即使没有独占的程序,甚至还会扰乱正在执行的程序。
1. 原理
以下是在RK3568上实现单实例程序的基本思路:
利用共享内存,开辟一块区域给程序使用。
当程序运行时,检查共享内存是否存在:
如果不存在则表明之前程序没有运行过,或者已经正常退出,此时初始化共享内存区域,并向其中写入当前时间戳;
如果存在,检查该区域内的数据与当前时间戳的差值,如果小于给定阈值,则表明已有实例在运行,当前程序退出;
如果差值大于给定阈值,则认为是之前同样实例的程序非正常退出,此时更新其中数据为当前时间戳;
程序在运行时,定时写入当前时间戳到共享内存中;
程序退出时,回收共享内存。
2. 实现
使用QT的共享内存方案,主要代码如下:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
tim=new QTimer();
connect(tim,SIGNAL(timeout()),this,SLOT(updateData()));
shm=new QSharedMemory(this);
shm->setKey(QString("XD_SINGLE_INSTANCE"));
//if can attach,
if(shm->attach())
{
char dat;
memset(dat,0x00,SHM_SIZE);
//retrive previous timestamp
shm->lock();
memmove(dat,shm->constData(),SHM_SIZE);
shm->unlock();
qint64* pre_ts=(qint64*)(dat);
//then check timestamp
if(QDateTime::currentMSecsSinceEpoch()-(*pre_ts)<2*INTERVAL)//epoch is very near
{
//so current instance should quit
qDebug()<<"previous instance running normally, i quit";
exit(1);
}
else//epoch diff too much
{
//so current instance should run & update
qDebug()<<"previous instance crashed,i run";
updateData();
tim->start(INTERVAL);
}
}
else
{
/*
* if can not attach due to not found key, that means:
* 1. this instance has never run before;
* 2. this instance has quit normally;
* either way, create & attach
*/
if(shm->error()==QSharedMemory::NotFound)
{
qDebug()<<"no instance is running, i run";
shm->create(SHM_SIZE);
updateData();
tim->start(INTERVAL);
}
}
}
Widget::~Widget()
{
if(shm!=nullptr)
{
shm->detach();
delete shm;
shm=nullptr;
}
delete ui;
}
void Widget::updateData()
{
qint64 ts=QDateTime::currentMSecsSinceEpoch();
//write current timestamp to shared memory
if(shm->isAttached())
{
shm->lock();
memmove(shm->data(),(void *)(&ts),SHM_SIZE);
shm->unlock();
qDebug().noquote()<<"update shared memory with Timestamp ="<<ts;
}
}
3. 编译运行与测试
自然还是熟悉的qmake和make:
在Debian环境下运行:
之前没有实例运行,程序正常运行
已有实例运行,退出
另一个实例非正常退出后,启动新实例
可以看到,在这几种情况下实例程序都得到了正确的识别与运行。当然,这个示例主要是用于阐述程序的原理,窗口程序并未有什么实际的作用,此外,向终端中打印时间戳也不是必须的,主要是为了阐述原理。
页:
[1]