Qt只启动一个实例

         阅读(439)  2017-09-18 17:52:14

要想实现这个需求,就涉及到进程间通信了,怎样让当前启动的程序知道在它之前有没有程序在运行。 其实实现方法还是蛮多的,简单介绍几种:

  • 两个进程读写同一个文件
  • 创建一个有名字的事件CreateEvent
  • 共享内存

下面是第三种方案的实现代码:

#ifndef RUNGUARD_H
#define RUNGUARD_H

#include <QObject>
#include <QSharedMemory>
#include <QSystemSemaphore>


class RunGuard
{

public:
	RunGuard(const QString& key);
	~RunGuard();

	bool isAnotherRunning();
	bool tryToRun();
	void release();

private:
	const QString key;
	const QString memLockKey;
	const QString sharedmemKey;

	QSharedMemory sharedMem;
	QSystemSemaphore memLock;

	Q_DISABLE_COPY(RunGuard)
};


#endif // RUNGUARD_H
#include "RunGuard.h"

#include <QCryptographicHash>


namespace
{

	QString generateKeyHash(const QString& key, const QString& salt)
	{
		QByteArray data;

		data.append(key.toUtf8());
		data.append(salt.toUtf8());
		data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();

		return data;
	}

}


RunGuard::RunGuard(const QString& key)
	: key(key)
	, memLockKey(generateKeyHash(key, "_memLockKey"))
	, sharedmemKey(generateKeyHash(key, "_sharedmemKey"))
	, sharedMem(sharedmemKey)
	, memLock(memLockKey, 1)
{
	memLock.acquire();
	{
		QSharedMemory fix(sharedmemKey);
		fix.attach();
	}
	memLock.release();
}

RunGuard::~RunGuard()
{
	release();
}

bool RunGuard::isAnotherRunning()
{
	if (sharedMem.isAttached())
		return false;

	memLock.acquire();
	const bool isRunning = sharedMem.attach();
	if (isRunning)
		sharedMem.detach();
	memLock.release();

	return isRunning;
}

bool RunGuard::tryToRun()
{
	if (isAnotherRunning())   // Extra check
		return false;

	memLock.acquire();
	const bool result = sharedMem.create(sizeof(quint64));
	memLock.release();
	if (!result)
	{
		release();
		return false;
	}

	return true;
}

void RunGuard::release()
{
	memLock.acquire();
	if (sharedMem.isAttached())
		sharedMem.detach();
	memLock.release();
}
  • QSystemSemaphore
    信号量保证进程间的原子操作,当有多个进程同时访问同一块共享内存时是有问题的,所以要保证共享内存的原子操作

  • QSharedMemory
    共享内存,如果isAttached为false说明没有其他的进程在运行,然后自身再attach这个共享内存,那么在下一个进程启动的时候就会发现isAttached为true

用法:

	RunGuard guard("69619FA7-4944-4CCA-BF69-83323F34D32F");
	if (!guard.tryToRun()) {
		return 0;
	}

69619FA7-4944-4CCA-BF69-83323F34D32F使用工具生成的随机GUID,你可以填任意字符串

文章评论

Keep it simple,stupid
文章数
284
总访问量
263318
今日访问
231
最近评论

ningto : 请到next.ningto.com里发表评论。
tujiaw : 抱歉csdn code服务关闭了,这个代码我也找不到了
于淞 : 你好,这个文章的源码能分享一下吗,songsong9181@163.com,谢谢了 上面的写错了
于淞 : 你好,这个文章的源码能分享一下吗,838106303@163.com,谢谢了 上面的链接不能用了
tujiaw : 多谢多谢
essaypinglun college-paper.org : 很好的博客,赞赞
Folly : 这个实现有点奇怪,Qt为什么没有统一的比对方法。
过多s : alert("hello, world!")
tujiaw : 还不错哦
回到顶部