Qt之运行一个实例进程

简述

发布程序的时候,我们往往会遇到这种情况:

  1. 只需要用户运行一个实例进程
  2. 用户可以同时运行多个实例进程

一个实例进程的软件有很多,例如:360、酷狗…
多个实例进程的软件也很多,例如:Visual Studio、Qt Ctretor、QQ…

下面我们来介绍下如何实现一个实例进程。

QSharedMemory

使用共享内存来实现,key值唯一,一般可以用组织名+应用名来确定。

首先,创建一个共享内存区,当第二个进程启动时,判断内存区数据是否建立,如果有,可以激活已打开的窗体,也可以退出。

当程序crash的时候,不能及时清除共享区数据,导致程序以后不能正常启动。

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

    QCoreApplication::setOrganizationName("Company");
    QCoreApplication::setApplicationName("AppName");
    QString strKey = QCoreApplication::organizationName() + QCoreApplication::applicationName();

    QSharedMemory sharedMemory(strKey);
    if (!sharedMemory.create(512,QSharedMemory::ReadWrite))
    {
        QMessageBox::information(NULL,QStringLiteral("提示"),QStringLiteral("程序已运行!"));
        exit(0);
    }

    MainWindow window;
    window.show();

    return app.exec();
}

QLocalServer

QSingleApplication.h

#ifndef SINGLE_APPLICATION_H
#define SINGLE_APPLICATION_H

#include <QApplication>

class QLocalServer;

class QSingleApplication : public QApplication
{
    Q_OBJECT

public:
    explicit QSingleApplication(int argc,char **argv);
    // 判断进程是否存在
    bool isRunning();

private slots:
    void newLocalConnection();

private:
    QLocalServer *m_pServer;
    bool m_bRunning;
};

#endif // SINGLE_APPLICATION_H

QSingleApplication.cpp

#include <QLocalSocket>
#include <QLocalServer>
#include <QFile>
#include <QTextStream>
#include "QSingleApplication.h"

QSingleApplication::QSingleApplication(int argc,char **argv)
    : QApplication(argc,argv),m_bRunning(false)
{
    QCoreApplication::setOrganizationName("Company");
    QCoreApplication::setApplicationName("AppName");
    QString strServerName = QCoreApplication::organizationName() + QCoreApplication::applicationName();

    QLocalSocket socket;
    socket.connectToServer(strServerName);

    if (socket.waitForConnected(500))
    {
        QTextStream stream(&socket);
        QStringList args = QCoreApplication::arguments();

        QString strArg = (args.count() > 1) ? args.last() : "";
        stream << strArg;
        stream.flush();
        qDebug() << "Have already connected to server.";

        socket.waitForBytesWritten();

        m_bRunning = true;
    }
    else
    {
        // 如果不能连接到服务器,则创建一个
        m_pServer = new QLocalServer(this);
        connect(m_pServer,SIGNAL(newConnection()),this,SLOT(newLocalConnection()));

        if (m_pServer->listen(strServerName))
        {
            // 防止程序崩溃,残留进程服务,直接移除
            if ((m_pServer->serverError() == QAbstractSocket::AddressInUseError) && QFile::exists(m_pServer->serverName()))
            {
                QFile::remove(m_pServer->serverName());
                m_pServer->listen(strServerName);
            }
        }
    }
}

void QSingleApplication::newLocalConnection()
{
    QLocalSocket *pSocket = m_pServer->nextPendingConnection();
    if (pSocket != NULL)
    {
        pSocket->waitForReadyRead(1000);

        QTextStream in(pSocket);
        QString strValue;
        in >> strValue;
        qDebug() << QString("The value is: %1").arg(strValue);

        delete pSocket;
        pSocket = NULL;
    }
}

bool QSingleApplication::isRunning()
{
    return m_bRunning;
}

使用方式

int main(int argc,char **argv)
{
    QSingleApplication app(argc,argv);
    if (app.isRunning())
    {
        QMessageBox::information(NULL,QStringLiteral("程序已运行!"));
        exit(0);
    }

    MainWindow window;
    window.show();

    return app.exec();
}

QtSingleApplication

QSingleApplication位于qt-solution里面,并不包含在Qt库中,遵循 LGPL 协议。

文档、源码、示例见:QtSingleApplication

任务列表

运行程序时,遍历任务列表,查看是当前所有运行中的进程,如果当前进程位置在映射路径中可以找到,则说明程序已经运行,否则,未运行。

更多参考

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结