Qt应用程序的单例化(程序只运行一个实例)

应用程序的单例化,顾名思义,就是有且只有一个应用程序实例存在。
现在了解到的单例化方式有三种,分别通过共享内存、QtSingleApplication、文件锁实现

个人推荐使用文件锁,比较方便,快捷

1、文件锁(QLockFile)

文件锁的方式就是程序在启动时先检测是否有文件锁存在且文件锁是否有效来达到锁定程序的目的。
主要通过QLockFile实现,关键代码:

    // 本测试程序id取名为SingleApp
    QString path = QDir::temp().absoluteFilePath("SingleApp.lock");
    QLockFile lockFile(path);

    bool isLock = lockFile.isLocked();
    (void)isLock; // 没什么实际意义
    // tryLock尝试创建锁定文件。此函数如果获得锁,则返回true; 否则返回false。
    // 如果另一个进程(或另一个线程)已经创建了锁文件,则此函数将最多等待timeout毫秒
    if (!lockFile.tryLock(100))
    {
        qDebug() << "已运行中";
        return 0;
    }

2、共享内存

共享内存的方式在实际使用中发现,如果程序奔溃或者其他程序将程序杀掉的话,会出现共享内存不释放的情况,也可能是使用方法有问题(如果使用方法有问题请指出,不胜感谢)

	// 使用共享内存,当第二个进程启动时,判断内存区数据是否建立,如有。则退出;
	// 这种方式有弊端,在程序发生崩溃时,未及时清除共享区数据,导致程序不能正常启动。

	// 信号量的意义,把操作共享内存的代码锁住。因为有可能同时点击2次APP, 防止并发  
	QSystemSemaphore sema("SingleApp Key", 1, QSystemSemaphore::Open);  
	sema.acquire();  

#ifdef Q_OS_LINUX  
    /*  Windows平台上不存在应用程序崩溃后,共享内存段还存在的情况 
     *  LINUX应用程序崩溃后,共享内存段不会自动销毁,则该程序再次运行会出问题 
     *  所以程序启动时先去检查是否有程序崩溃后还存留的共享内存段,如果有,先销毁,再创建 
     */  
    QSharedMemory mem("SingleApp");  
    // 尝试将进程附加到共享内存段  
    if (mem.attach()) 
    {  
        // 将共享内存与主进程分离, 如果此进程是附加到共享存储器段的最后一个进程,则系统释放共享存储器段,即销毁内容  
        mem.detach();  
    }  
#endif  
  
    /* 
     * 每个App打开的时候,获取一次共享内存。 
     * 如果获取失败,说明是第一个启动的APP,直接创建共享内存就好了。 
     * 如果获取成功,说明不是第一个,直接退出就好了。 
     * 保证App在系统里只能打开一个。 
     */  
    QSharedMemory unimem("SingleApp");  
    bool isRunning = false;  
    if (unimem.attach())  
    	isRunning = true;   
    else 
    {  
        unimem.create(1);  
        isRunning = false;  
    }  
    sema.release();  
      
    if (isRunning)
    {  
        QMessageBox::warning(nullptr, "warning", "The app is running.");  
        exit(0);  
    }  

3、QtSingleApplication

这个实现单例化主要依赖的是本地socket(QLocalSocket/QLocalServer)实现,所以需要依赖QNetWork模块
具体使用方式:

1、在.pro中操作

QT       += network
include(../qtsingleapplication.pri) //qtsingleapplication放在工程目录的情况下 

2、main函数里面的修改,将以前QApplication改为QtSingleApplication

#include "mainwindow.h"
#include "QtSingleApplication.h"
int main(int argc, char *argv[])
{

	QtSingleApplication a("myapp_id",argc, argv);
	if(a.isRunning())                  //判断实例是否已经运行
	{
		qDebug()<<"this is already running";
		a.sendMessage("raise_window_noop", 4000); //4s后激活前个实例
		return 0;
	}
	MainWindow w;
	a.setActivationWindow(&w,1);          //如果是第一个实例,则绑定,方便下次调用 
	w.show();

	return a.exec();
}

参考资料:

官方:http://code.qt.io/cgit/qt-solutions/qt-solutions.git/

官方资料:http://doc.qt.io/archives/qtextended4.4/qtopiadesktop/qtsingleapplication.html#sendMessage

下载地址:
百度网盘地址:https://pan.baidu.com/s/17ICn7_PeYieWDgi9aDWRXA提取码: vkde

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章