應用程序的單例化,顧名思義,就是有且只有一個應用程序實例存在。
現在瞭解到的單例化方式有三種,分別通過共享內存、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