📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

ページの作成:「== 概要 == ソフトウェアのインスタンスを1つだけ実行(多重起動を禁止)する理由として、<br> メモリリークの問題を制限する、…」
 
文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の7版が非表示)
137行目: 137行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>
== QLocalServer / QLocalSocketの使用 ==
まず、<code>QSharedMemory</code>クラスを使用して、アプリケーションの起動時に単一のインスタンスのみが実行されることを保証する。<br>
<br>
次に、アプリケーションが起動する時、まず共有メモリへのアタッチを試みる。<br>
成功した場合は、これは既に別のインスタンスが実行中であることを意味するため、新しいインスタンスは即座に終了する。<br>
一方、アタッチに失敗した場合は、アプリケーションは新しい共有メモリセグメントを生成しようとする。<br>
新しい共有メモリセグメントの生成が成功した場合は、現在のインスタンスが最初の実行であると判断する。<br>
<br>
また、単に多重起動を防ぐだけでなく、既存のインスタンスと新規インスタンス間でコミュニケーションを取ることも重要である。<br>
これを、<code>QLocalServer</code>と<code>QLocalSocket</code>を使用して行う。<br>
# 最初のインスタンスは、<code>QLocalServer</code>を使用してローカルサーバを起動する。
# このローカルサーバは、特定のキー (例: "/tmp/MyAppServer") で識別される。
# その後、新規インスタンスが起動しようとした場合、<code>QLocalSocket</code>を使用して既存のインスタンスに接続を試みる。
# 接続が確立された場合、新しいインスタンスは既存のインスタンスにメッセージを送信する。<br>例えば、「新しいインスタンスが起動を試みました」といったメッセージを送信することができる。
# 既存のインスタンス側では、このメッセージを受信して、適切に対応することができる。<br>例えば、アプリケーションウィンドウを前面に持ってくる等の動作が考えられる。
<br>
QLocalServer / QLocalSocketを使用したメリットは、単に多重起動を防ぐだけでなく、ユーザの意図 (新しいインスタンスを起動しようとした) を既存のインスタンスに伝達できる点である。<br>
既存のインスタンスと通信する機能により、ユーザエクスペリエンスを向上させることができ、より柔軟で拡張性の高い設計になっている。<br>
<br>
処理の流れを以下に示す。<br>
# <code>QSharedMemory</code>を使用して、アプリケーションの単一インスタンスを保証する。
# <code>QLocalServer</code>と<code>QLocalSocket</code>を使用して、既存のインスタンスと新しいインスタンス間で通信を行う。
# SingleInstanceクラスのインスタンスを生成して、単一インスタンス制御のロジックをカプセル化する。
# SingleInstanceクラスのtryToRunメソッド実行して、アプリケーションが実行可能かどうかを確認する。
# 既存のインスタンスが検出された場合、sendMessagスロットを使用してそのインスタンスにメッセージを送信する。<br><u>ロック向け一時ファイルが、/tmp/MyAppServerファイルが自動的に生成される。</u>
# 既存のインスタンスは、messageReceivedシグナルを通じてメッセージを受信して、適切に対応する。<br>(例: ウインドウのアクティブ化等)
<br>
必要に応じて、messageReceivedシグナルのハンドラを拡張して、既存のウインドウをアクティブにする等の処理を追加する。<br>
<br>
<code>QLocalServer</code>と<code>QLocalSocket</code>を使用するには、Qt Networkモジュールが必要となる。<br>
* Qtプロジェクトファイル (.pro) を使用する場合
<syntaxhighlight lang="make">
QT += network
</syntaxhighlight>
<br>
* CMakeLists.txtファイルを使用する場合
<syntaxhighlight lang="cmake">
find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(<ターゲット名> PRIVATE
    Qt6::Network
)
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// SingletonInstance.hファイル
#include <QLocalServer>
#include <QLocalSocket>
#include <QSharedMemory>
#include <QDataStream>
class SingletonInstance : public QObject
{
    Q_OBJECT
private:
    QString        m_key;
    QSharedMemory  m_sharedMemory;
    QLocalServer    *m_pServer;
public:
    SingletonInstance(const QString &key) : m_key(key), m_sharedMemory(key), m_pServer(new QLocalServer(this))
    {
      connect(m_pServer, &QLocalServer::newConnection, this, &SingletonInstance::handleConnection);
    }
    bool tryToRun()
    {
      if (m_sharedMemory.attach()) {
          return false;  // 別のインスタンスが既に実行中
      }
      if (!m_sharedMemory.create(1)) {
          return false;  // 共有メモリの作成に失敗
      }
      if (!m_pServer->listen(m_key)) {
          return false;  // サーバの起動に失敗
      }
      return true;
    }
public slots:
    void sendMessage(const QString &message)
    {
      QLocalSocket socket;
      socket.connectToServer(m_key);
      if (socket.waitForConnected(1000)) {
          QByteArray block;
          QDataStream out(&block, QIODevice::WriteOnly);
          out << message;
          socket.write(block);
          socket.flush();
          socket.waitForBytesWritten();
          socket.disconnectFromServer();
      }
    }
signals:
    void messageReceived(const QString &message);
private slots:
    void handleConnection()
    {
      QLocalSocket *pSocket = m_pServer->nextPendingConnection();
      if (pSocket) {
          connect(pSocket, &QLocalSocket::readyRead, this, [this, pSocket]() {
              QDataStream in(pSocket);
              QString message;
              in >> message;
              emit messageReceived(message);
              pSocket->deleteLater();
          });
      }
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QApplication>
#include <QMessageBox>
#include "mainwindow.h"
#include "SingletonInstance.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    SingletonInstance instance("/tmp/MyAppServer");
    if (!instance.tryToRun()) {
      // 別のインスタンスが既に実行中の場合、メッセージを送信して終了
      QMessageBox::warning(nullptr, "多重起動エラー", "多重起動を検出しました", QMessageBox::Ok);
      instance.sendMessage("新しいインスタンスが起動を試みました");
      return -1;
    }
    // 最初のインスタンスの場合、メインウィンドウをセットアップしてアプリケーションを実行
    QObject::connect(&instance, &SingletonInstance::messageReceived, [](const QString &message) {
      qDebug() << "受信したメッセージ: " << message;
      // ここでメッセージを処理する
      // 例: ウインドウを前面に表示する等
    });
    // メインウインドウのセットアップをここに記述
    MainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}
</syntaxhighlight>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]