所谓程序单例,也就是在电脑上只允许一个程序只有一个实例在运行。
在QT环境中,实现程序单例的方法一般是这样的:程序启动的时候,先判断指定了key的共享内存是否可以attach,如果可以,则证明已经有一个实例在运行,否则就创建一块共享内存。
AppSingleton
实现逻辑:创建一块共享内存,启动定时器检查共享内存的数据,来判断是否有新的信号进来。
app_singleton.h
#pragma once
#include <QApplication>
#include <QSharedMemory>
class AppSingleton : public QApplication
{
Q_OBJECT
public:
AppSingleton(int& argc, char* argv[], const QString uniqueKey);
bool isRunning();
bool sendMessage(const QString& message);
signals:
void signalMessageAvailable(QString message);
public slots:
void checkForMessage();
private:
bool is_running_;
QSharedMemory shared_memory_;
};
app_singleton.cpp
#include "app_singleton.h"
#include <QTimer>
#include <QByteArray>
AppSingleton::AppSingleton(int& argc, char* argv[], const QString uniqueKey)
: QApplication(argc, argv)
{
shared_memory_.setKey(uniqueKey);
if (shared_memory_.attach())
{
is_running_ = true;
}
else
{
is_running_ = false;
QByteArray byteArray("0");
if (!shared_memory_.create(byteArray.size()))
{
qDebug("Unable to create single instance.");
return;
}
shared_memory_.lock();
char* to = (char*)shared_memory_.data();
const char* from = byteArray.data();
memcpy(to, from, qMin(shared_memory_.size(), byteArray.size()));
shared_memory_.unlock();
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(checkForMessage()));
timer->start(1000);
}
}
void AppSingleton::checkForMessage()
{
shared_memory_.lock();
QByteArray byteArray = QByteArray((char*)shared_memory_.constData(), shared_memory_.size());
shared_memory_.unlock();
if (byteArray.left(1) == "0")
return;
byteArray.remove(0, 1);
QString message = QString::fromUtf8(byteArray.constData());
emit signalMessageAvailable(message);
byteArray = "0";
shared_memory_.lock();
char* to = (char*)shared_memory_.data();
const char* from = byteArray.data();
memcpy(to, from, qMin(shared_memory_.size(), byteArray.size()));
shared_memory_.unlock();
}
bool AppSingleton::isRunning()
{
return is_running_;
}
bool AppSingleton::sendMessage(const QString& message)
{
if (!is_running_)
return false;
QByteArray byteArray("1");
byteArray.append(message.toUtf8());
byteArray.append('\0');
shared_memory_.lock();
char* to = (char*)shared_memory_.data();
const char* from = byteArray.data();
memcpy(to, from, qMin(shared_memory_.size(), byteArray.size()));
shared_memory_.unlock();
return true;
}
SingleApplication
实现逻辑:创建一块共享内存和QLocalServer,监听是否有新的连接进来。
single_application.h
#pragma once
#include <QApplication>
#include <QSharedMemory>
#include <QLocalServer>
class SingleApplication : public QApplication
{
Q_OBJECT
public:
SingleApplication(int& argc, char* argv[], const QString uniqueKey);
bool isRunning();
bool sendMessage(const QString& message);
signals:
void signalMessageAvailable(QString message);
public slots:
void onNewConnection();
private:
bool is_running_;
QString unique_key_;
QSharedMemory shared_memory_;
QLocalServer* local_server_;
static const int timeout_ = 1000;
};
single_application.cpp
#include "single_application.h"
#include <QLocalSocket>
#pragma execution_character_set("utf-8")
SingleApplication::SingleApplication(int& argc, char* argv[], const QString uniqueKey)
: QApplication(argc, argv)
, unique_key_(uniqueKey)
{
shared_memory_.setKey(unique_key_);
if (shared_memory_.attach())
{
is_running_ = true;
}
else
{
is_running_ = false;
if (!shared_memory_.create(1))
{
qDebug("Unable to create single instance.");
return;
}
local_server_ = new QLocalServer(this);
connect(local_server_, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
local_server_->listen(unique_key_);
}
}
void SingleApplication::onNewConnection()
{
QLocalSocket* localSocket = local_server_->nextPendingConnection();
if (!localSocket->waitForReadyRead(timeout_))
{
qDebug(localSocket->errorString().toLatin1());
return;
}
QByteArray byteArray = localSocket->readAll();
QString message = QString::fromUtf8(byteArray.constData());
emit signalMessageAvailable(message);
localSocket->disconnectFromServer();
}
bool SingleApplication::isRunning()
{
return is_running_;
}
bool SingleApplication::sendMessage(const QString& message)
{
if (!is_running_)
return false;
QLocalSocket localSocket(this);
localSocket.connectToServer(unique_key_, QIODevice::WriteOnly);
if (!localSocket.waitForConnected(timeout_))
{
qDebug(localSocket.errorString().toLatin1());
return false;
}
localSocket.write(message.toUtf8());
if (!localSocket.waitForBytesWritten(timeout_))
{
qDebug(localSocket.errorString().toLatin1());
return false;
}
localSocket.disconnectFromServer();
return true;
}
测试程序
int main(int argc, char *argv[])
{
SingleApplication a(argc, argv, "6DE75305-A822-459E-9EDA-E8B038908966");
if (a.isRunning())
{
a.sendMessage(BugReport::tr("Only one program instance is allowed to run."));
return 0;
}
YourApp w;
QObject::connect(&a, SIGNAL(signalMessageAvailable(QString)), &w, SLOT(slotMessageAvailable(QString)));
w.show();
return a.exec();
}
|