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

Qt一个功能强大的C++跨平台应用程序开发框架。Qt中提供了单例模式的实现方法,在Qt中实现一个单例需要使用Q_GLOBAL_STATIC宏来创建单例,并使用connect()连接信号和槽。 全局信号是指可以被应用程序中的任何对象接收的信号。由于应用程序中的对象可以在应用程序的不同线程中运行,因此使用单例模式实现全局信号是一个很好的解决方案。 单例模式是一种创建单个实例的方式,确保只有一个实例被创建并在应用程序的整个生命周期中使用。Qt中使用Q_GLOBAL_STATIC宏定义单例,该宏的第一个参数是单例类的类型。 例如,下面的代码定义了一个名为MySingleton的单例类: ``` class MySingleton { public: static MySingleton* getInstance(); private: MySingleton(); Q_DISABLE_COPY(MySingleton) }; MySingleton *MySingleton::getInstance() { static const QScopedPointer<MySingleton> instance(new MySingleton()); return instance.data(); } typedef QGlobalStatic<MySingleton> MySingletonPtr; Q_GLOBAL_STATIC(MySingletonPtr, mySingleton) ``` 全局信号可以使用Qt中的QObject类来实现。QObject类中定义了signal和slot,可以在应用程序中的不同对象之间传递消息和数据。 为了实现全局信号,可以在单例类中添加一个QObject对象,并在其中定义信号和槽。在接收信号的对象中,可以使用connect()函数将对象的槽函数连接到全局信号。 例如,下面的代码向MySingleton类中添加了一个QObject对象,并定义一个全局信号: ``` class MySingleton : public QObject { public: static MySingleton* getInstance(); signals: void mySignal(); private: MySingleton(); Q_DISABLE_COPY(MySingleton) }; MySingleton *MySingleton::getInstance() { static const QScopedPointer<MySingleton> instance(new MySingleton()); return instance.data(); } typedef QGlobalStatic<MySingleton> MySingletonPtr; Q_GLOBAL_STATIC(MySingletonPtr, mySingleton) MySingleton::MySingleton() : QObject() {} ``` 现在,就可以在应用程序中的其他对象中接收全局信号: ``` MySingleton::getInstance()->emit mySignal(); ``` 可以将mySignal()信号连接到任何具有匹配参数的槽函数中: ``` connect(MySingleton::getInstance(), &MySingleton::mySignal, this, &MyObject::mySlot); ``` 使用单例模式和QObject类,Qt可以非常方便地实现全局信号。通过这种方式,任何对象都可以接收应用程序中发生的事件,从而更加灵活和可扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值