查看: 311|回复: 0

[评测分享] 【米尔-MYD-LR3568-GK开发板--试用评测】20——单实例程序

[复制链接]
  • TA的每日心情
    慵懒
    昨天 10:54
  • 签到天数: 186 天

    连续签到: 2 天

    [LV.7]常住居民III

    发表于 2024-12-2 22:07:23 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 stm1024 于 2024-12-2 22:09 编辑

    单实例程序是一种设计模式,用于确保一个应用程序或服务的只有一个实例在运行。常见于桌面应用程序中,尤其是在需要确保不重复打开多个窗口或会话的情况下,例如有独占硬件资源的程序,再打开一个程序已经毫无意义,只会浪费系统资源和报错;或者即使没有独占的程序,甚至还会扰乱正在执行的程序。
    1. 原理
    以下是在RK3568上实现单实例程序的基本思路:

    利用共享内存,开辟一块区域给程序使用。
    当程序运行时,检查共享内存是否存在:
        如果不存在则表明之前程序没有运行过,或者已经正常退出,此时初始化共享内存区域,并向其中写入当前时间戳;
        如果存在,检查该区域内的数据与当前时间戳的差值,如果小于给定阈值,则表明已有实例在运行,当前程序退出;
               如果差值大于给定阈值,则认为是之前同样实例的程序非正常退出,此时更新其中数据为当前时间戳;
        程序在运行时,定时写入当前时间戳到共享内存中;
        程序退出时,回收共享内存。

    2. 实现
    使用QT的共享内存方案,主要代码如下:
    1. #include "widget.h"
    2. #include "ui_widget.h"

    3. Widget::Widget(QWidget *parent)
    4.     : QWidget(parent)
    5.     , ui(new Ui::Widget)
    6. {
    7.     ui->setupUi(this);
    8.     tim=new QTimer();
    9.     connect(tim,SIGNAL(timeout()),this,SLOT(updateData()));

    10.     shm=new QSharedMemory(this);
    11.     shm->setKey(QString("XD_SINGLE_INSTANCE"));
    12.     //if can attach,
    13.     if(shm->attach())
    14.     {
    15.         char dat[SHM_SIZE];
    16.         memset(dat,0x00,SHM_SIZE);
    17.         //retrive previous timestamp
    18.         shm->lock();
    19.         memmove(dat,shm->constData(),SHM_SIZE);
    20.         shm->unlock();
    21.         qint64* pre_ts=(qint64*)(dat);
    22.         //then check timestamp
    23.         if(QDateTime::currentMSecsSinceEpoch()-(*pre_ts)<2*INTERVAL)//epoch is very near
    24.         {
    25.             //so current instance should quit
    26.             qDebug()<<"previous instance running normally, i quit";
    27.             exit(1);
    28.         }
    29.         else//epoch diff too much
    30.         {
    31.             //so current instance should run & update
    32.             qDebug()<<"previous instance crashed,i run";
    33.             updateData();
    34.             tim->start(INTERVAL);
    35.         }
    36.     }
    37.     else
    38.     {
    39.         /*
    40.          * if can not attach due to not found key, that means:
    41.          * 1. this instance has never run before;
    42.          * 2. this instance has quit normally;
    43.          * either way, create & attach
    44.         */
    45.         if(shm->error()==QSharedMemory::NotFound)
    46.         {
    47.             qDebug()<<"no instance is running, i run";
    48.             shm->create(SHM_SIZE);
    49.             updateData();
    50.             tim->start(INTERVAL);
    51.         }
    52.     }
    53. }

    54. Widget::~Widget()
    55. {
    56.     if(shm!=nullptr)
    57.     {
    58.         shm->detach();
    59.         delete shm;
    60.         shm=nullptr;
    61.     }
    62.     delete ui;
    63. }

    64. void Widget::updateData()
    65. {
    66.     qint64 ts=QDateTime::currentMSecsSinceEpoch();
    67.     //write current timestamp to shared memory
    68.     if(shm->isAttached())
    69.     {
    70.         shm->lock();
    71.         memmove(shm->data(),(void *)(&ts),SHM_SIZE);
    72.         shm->unlock();
    73.         qDebug().noquote()<<"update shared memory with Timestamp ="<<ts;
    74.     }
    75. }
    复制代码
    3. 编译运行与测试
    自然还是熟悉的qmake和make:
    111.jpg


    在Debian环境下运行:
    222.png
    之前没有实例运行,程序正常运行

    333.png
    已有实例运行,退出

    444.png

    另一个实例非正常退出后,启动新实例

    可以看到,在这几种情况下实例程序都得到了正确的识别与运行。当然,这个示例主要是用于阐述程序的原理,窗口程序并未有什么实际的作用,此外,向终端中打印时间戳也不是必须的,主要是为了阐述原理。

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /5 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-12-23 21:58 , Processed in 0.122091 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.