使Qt 程序只能运行一个实例的3种方法

43 篇文章 14 订阅

1. 共享内存的方法

Unix: QSharedMemory "owns" the shared memory segment. When the last thread or process that has an instance of QSharedMemory attached to a particular shared memory segment detaches from the segment by destroying its instance of QSharedMemory, the Unix kernel release the shared memory segment. But if that last thread or process crashes without running the QSharedMemory destructor, the shared memory segment survives the crash.

(据说这种方法在Linux系统下会有一个内存释放的问题,在某种情况下会引起程序的异常或崩溃)

 
// 确保只运行一次 

QSystemSemaphore sema("JAMKey",1,QSystemSemaphore::Open); 
sema.acquire();// 在临界区操作共享内存   SharedMemory 

QSharedMemory mem("SystemObject");// 全局对象名 
if (!mem.create(1))// 如果全局对象以存在则退出 
{ 
    QMessageBox::information(0, MESSAGEBOXTXT,"An instance has already been running.");
 
    sema.release();// 如果是 Unix 系统,会自动释放。 

    return 0; 
} 

sema.release();// 临界区 


2. 使用QLocalServer和QLocalSocket类

下面是自已的写的代码,主要是在运行第二实例的时候,有一个提示的作用:

1. 切换到当前程序,并将当前程序最大化显示到前面。

2.关闭当前程序的进程,打开新程序。

(注意:需要在你的.pro里加上QT += network)

头文件:
#ifndef PSA_USR_LOGIN_H
#define PSA_USR_LOGIN_H

#include <QDialog>
#include <QTimeLine>
#include <QLocalServer>

#include "ui_DlgUsrLogin.h"

#define PROCESS_SHOW		1
#define PROCESS_RESTART		2
#define PROCESS_STOP		3

const QString PRO_SHOW		= "PRO_SHOW";
const QString PRO_RESTART	= "PRO_RESTART";
const QString PRO_STOP		= "PRO_STOP";

class CUsrLogin : public QDialog
{
	Q_OBJECT

public:
	CUsrLogin(const QString& serverName, QWidget* parent = NULL);
	virtual ~CUsrLogin();

	int GetIndex() const;
	bool InitServer();

signals:
	void sig_newOrder(const QString&);

private slots:
	void slot_ok();
	void slot_cancel();
	void slot_btnGroupClicked(int);
	void slot_newConnection();
	void slot_readyRead();
	void slot_timeFinished();

private:
	int IsServerRun(const QString & servername);

private:
	Ui::DlgUsrLogin ui;

	int mIndex;
	QString mServerName;
	QLocalServer* mpServer;
	QTimeLine *mpTimeLine;
};

#endif
源文件:
#include "psa_usr_login.h"
#include <QButtonGroup>
#include <QLocalSocket>

CUsrLogin::CUsrLogin( const QString& serverName, QWidget* parent /*= NULL*/ )
	: QDialog(parent)
	, mpServer(NULL)
	, mpTimeLine(NULL)
{
	ui.setupUi(this);

	mIndex = 1;
	mServerName = serverName;

	QButtonGroup* btnGroup = new QButtonGroup;
	btnGroup->addButton(ui.btn_showCurPro,  PROCESS_SHOW);
	btnGroup->addButton(ui.btn_openNewPro,  PROCESS_RESTART);

	ui.progressBar->setVisible(false);
	mpTimeLine = new QTimeLine(3000, this);
	mpTimeLine->setFrameRange(0, 100);
	connect(mpTimeLine, SIGNAL(frameChanged(int)), ui.progressBar, SLOT(setValue(int)));
	connect(mpTimeLine, SIGNAL(finished()), this, SLOT(slot_timeFinished()));

	connect(btnGroup, SIGNAL(buttonPressed(int)), this, SLOT(slot_btnGroupClicked(int)));
	connect(ui.btn_ok, SIGNAL(clicked()), this, SLOT(slot_ok()));
	connect(ui.btn_cancel, SIGNAL(clicked()), this, SLOT(slot_cancel()));
}

CUsrLogin::~CUsrLogin()
{
	if(mpServer)
	{
		QLocalServer::removeServer(mServerName);
		delete mpServer;
		mpServer = NULL;
	}

	if(mpTimeLine)
	{
		mpTimeLine->stop();
		delete mpTimeLine;
		mpTimeLine = NULL;
	}
}

int CUsrLogin::GetIndex() const
{
	return mIndex;
}

void CUsrLogin::slot_ok()
{
    QLocalSocket ls;
	ls.connectToServer(mServerName);

	if (ls.waitForConnected())
	{
		switch(mIndex)
		{
		case PROCESS_SHOW:
			{
				char msg[25] = {0};
				memcpy(msg, PRO_SHOW.toStdString().c_str(), PRO_SHOW.length());
				ls.write(msg);
				ls.waitForBytesWritten();

				QDialog::accept();
				break;
			}
		case PROCESS_RESTART:
			{
				char msg[25] = {0};
				memcpy(msg, PRO_RESTART.toStdString().c_str(), PRO_RESTART.length());
				ls.write(msg);
				ls.waitForBytesWritten();

				ui.progressBar->setVisible(true);
				mpTimeLine->start();
				break;
			}
		case PROCESS_STOP:
			{
				char msg[25] = {0};
				memcpy(msg, PRO_STOP.toStdString().c_str(), PRO_STOP.length());
				ls.write(msg);
				ls.waitForBytesWritten();

				QDialog::accept();
				break;
			}
		default:
			QDialog::accept();
			break;
		}
	}
}

void CUsrLogin::slot_cancel()
{
	QDialog::reject();
}

void CUsrLogin::slot_btnGroupClicked( int idx)
{
	mIndex = idx;
}

void CUsrLogin::slot_readyRead()
{
	QLocalSocket *local = static_cast<QLocalSocket *>(sender());
	if (!local)
		return;

	QTextStream in(local);
	QString     readMsg;

	readMsg = in.readAll();

	emit sig_newOrder(readMsg);
}

// 判断是否有一个同名的服务器在运行
int CUsrLogin::IsServerRun(const QString & servername)
{        
	QLocalSocket ls;
	ls.connectToServer(servername);

	if (ls.waitForConnected(1000)) 
	{
		ls.disconnectFromServer();
		ls.close();
		return 1;
	}

	return 0;
}

bool CUsrLogin::InitServer()
{
	if (!IsServerRun(mServerName))
	{
		mpServer = new QLocalServer;
		QLocalServer::removeServer(mServerName);

		mpServer->listen(mServerName);
		connect(mpServer, SIGNAL(newConnection()), this, SLOT(slot_newConnection()));

		return true;
	}

	return false;
}

void CUsrLogin::slot_newConnection()
{
	QLocalSocket *newsocket = mpServer->nextPendingConnection();
	connect(newsocket, SIGNAL(readyRead()), this, SLOT(slot_readyRead()));
}

void CUsrLogin::slot_timeFinished()
{
	if(InitServer())
	{
		QDialog::accept();
	}
}
主函数:

在主函数中添加CUsrLogin.. 和 信号槽函数。

int main(int argc, char * argv[])
{
	QApplication app(argc, argv);

	QString name = "******"; // 自定义程序名称
	CUsrLogin login(name);
	if(!login.InitServer())
	{
		int ret = login.exec();
		if(QDialog::Accepted == ret)
		{
			if( login.GetIndex() == PROCESS_SHOW ||
				login.GetIndex() == PROCESS_STOP )
			{
				return 1;
			}
		}
		else
		{
			return 1;
		}
	}

	MainWindow mainWin;
	mainWin.show();

	QObject::connect(&login, SIGNAL(sig_newOrder(const QString&)), &mainWin, SLOT(slotProcAppMessage(const QString&)));

	return app.exec();
}

MainWindow中实现:
void MainWindow::slotProcAppMessage( const QString& order)
{
	if(order == PRO_SHOW)
	{
		#ifdef WIN32
		{
			activateWindow();
			showMinimized();
			showMaximized();
		}
		#else
		{
			activateWindow();

            if(windowState () & Qt::WindowMinimized)
            {   
                    setWindowState(windowState() & ~Qt::WindowMinimized | Qt::WindowActive);
                    showMaximized();
                    show();
            }
            else if(windowState() & Qt::WindowMaximized)
            {   
                    setWindowState(windowState() & Qt::WindowMaximized | Qt::WindowActive);
            }   
            else
            {   
                    setWindowState(windowState() & Qt::WindowMaximized | Qt::WindowActive);
            }
		}
		#endif
	}
	else if(order == PRO_RESTART)
	{
		close();
	}
	else if(order == PRO_STOP)
	{
		close();
	}
}

3. QSingleApplication类

实现原理应该和QLocalServer和QLocalSocket相同。

使用Qt中的QSharedMemory,QLocalServer和QLocalSocket实现(不过需要在你的.pro里加上QT += network)

具体说明可以参考:

http://blog.csdn.net/playstudy/article/details/7796691 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中,可以使用QApplication和QMutex类来确保同一台机器上只有一个实例运行。具体实现方法如下: 1. 在main函数中,先创建一个QSharedMemory对象,并给它一个唯一的键值。 2. 调用QSharedMemory的create函数,尝试创建该共享内存。如果返回false,则表示该共享内存已经被创建,说明已经有一个实例运行了,此时可以调用QSharedMemory的attach函数来连接到已经存在的共享内存。 3. 如果create函数返回true,则说明该共享内存还没有被创建,这个时候需要调用QApplication的exec函数来启动应用程序,并在程序退出时调用QSharedMemory的detach函数来释放共享内存。 4. 在程序执行过程中,可以使用QMutex来控制多个线程对共享内存的访问,确保同一时间只有一个线程在访问共享内存。 5. 当程序退出时,需要调用QSharedMemory的detach函数来释放共享内存,确保下次启动程序时可以重新创建共享内存。 下面是一个基本的示例代码: ```c++ #include <QApplication> #include <QSharedMemory> #include <QMessageBox> #include <QMutex> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建唯一的键值 const QString memKey = "MyApplicationKey"; // 创建共享内存 QSharedMemory sharedMem(memKey); // 尝试连接共享内存 if (!sharedMem.create(1)) { // 共享内存已经被创建,说明已经有一个实例运行 QMessageBox::critical(nullptr, "Error", "Another instance is already running!"); return 1; } // 创建互斥锁,确保同一时间只有一个线程在访问共享内存 QMutex mutex; mutex.lock(); // 启动应用程序 int ret = app.exec(); // 释放共享内存 sharedMem.detach(); return ret; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值