MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの応用 - 多重起動の禁止のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの応用 - 多重起動の禁止
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ソフトウェアのインスタンスを1つだけ実行(多重起動を禁止)する理由として、<br> メモリリークの問題を制限する、または、リソース、ファイル、データベース等をアプリケーションの2つのインスタンスが奪い合うことで起こる問題を排除するためである。<br> また、原則として、ユーザが使用するアプリケーションのコピーは1つだけでよい場合もある。<br> <br> 多重起動を禁止する方法には、以下に示す2つの方法がある。<br> * QLockFileの使用 *: 一時的なファイルが作成されて、ソフトウェア終了時に破棄する。 *: これは、ソフトウェアを多重起動された時、その一時ファイルの存在を確認して、一時ファイルが存在するならばインスタンスを自動的に閉じる。 *: <br> * QSystemSemaphoreとQSharedMemoryの使用 *: 共有メモリセグメントを作成して、一意の識別子を持つ既存のセグメントに接続する。 *: 接続に成功した場合、ソフトウェアのインスタンスが既に作成されているため、そのことをユーザに通知してソフトウェアを終了する。 *: 接続に失敗した場合、ソフトウェア用のメモリセグメントを作成して、最初のインスタンスを実行する。 <br><br> == QLockFileの使用 == ソフトウェアの起動時に作成された一時ファイル(Lock File)の作成に失敗する場合、<br> 既にソフトウェアのインスタンスが存在すると仮定して、ユーザに通知してソフトウェアを終了する。<br> <br> QLockFileは、ソフトウェアの実行インスタンスの数を制限する。<br> ただし、QLockFileの使用は、ユーザのパーミッションに問題がある場合は使用できない可能性がある。<br> <br> <u>※注意</u><br> <u><uniq id>は、任意のIDに置き換えること。</u> <syntaxhighlight lang="c++"> #include <QApplication> #include <QLockFile> #include <QDir> #include <QMessageBox> #include "CMainWindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QLockFile lockFile(QDir::temp().absoluteFilePath("<uniq id>.lock")); // Trying to close the Lock File, if the attempt is unsuccessful for 100 milliseconds, // then there is a Lock File already created by another process. // Therefore, we throw a warning and close the program if(!lockFile.tryLock(100)) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText("The application is already running.\n" "Allowed to run only one instance of the application."); msgBox.exec(); return -1; } CMainWindow w; w.show(); return a.exec(); } </syntaxhighlight> <br><br> == QSystemSemaphoreとQSharedMemoryの使用 == QSharedMemoryは、1台のPC上において、同時に作業しているすべてのユーザーに共有されるものである。<br> これは、システム全体として、ソフトウェアの単一インスタンスの実行を制限する場合等に使用する。<br> したがって、1人のユーザがソフトウェアを実行する場合、他のユーザは同一のソフトウェアを実行することはできない。<br> <br> しかし、各プラットフォームによる共有メモリの違いが存在する。<br> Windowsの場合、共有メモリはプログラムが正常に終了した時および緊急事態が発生した時に解放される。<br> Linux / Unixの場合、緊急時にクラッシュしたメモリは解放されない。<br> <br> 以下の例では、同一のソフトウェアの複数のインスタンスが同時に起動した場合の問題を解決するために使用される。<br> <br> セマフォはメータで作成されて、その最大数は1になる。<br> セマフォを解除する時、ソフトウェアの他の全てのインスタンスは共有メモリにアクセスできないため、完全に所有するリソースの1つのコピーを持つ。<br> このコピーは、ソフトウェアに対応する共有メモリセグメントの識別子の存在により、ソフトウェアの別のインスタンスの実行をチェックする。<br> 共有メモリセグメントのコピーは、正常に起動する時かつ別のソフトウェアインスタンスの情報が見つからない場合に作成される。<br> その後、セマフォが下げられて、実行するソフトウェアの別のインスタンスが許可される。<br> <br> <u>※注意</u><br> <u><uniq id 1>および<uniq id 2>は、任意のIDに置き換えること。</u> <syntaxhighlight lang="c++"> #include <QApplication> #include <QSystemSemaphore> #include <QSharedMemory> #include <QMessageBox> #include "CMainWindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QSystemSemaphore semaphore("<uniq id 1>", 1); // create semaphore semaphore.acquire(); // Raise the semaphore, barring other instances to work with shared memory #ifndef Q_OS_WIN32 // in linux / unix shared memory is not freed when the application terminates abnormally, // so you need to get rid of the garbage QSharedMemory nix_fix_shared_memory("<uniq id 2>"); if(nix_fix_shared_memory.attach()) { nix_fix_shared_memory.detach(); } #endif QSharedMemory sharedMemory("<uniq id 2>"); // Create a copy of the shared memory bool is_running; // variable to test the already running application if(sharedMemory.attach()) { // We are trying to attach a copy of the shared memory // To an existing segment is_running = true; // If successful, it determines that there is already a running instance } else { sharedMemory.create(1); // Otherwise allocate 1 byte of memory is_running = false; // And determines that another instance is not running } semaphore.release(); // If you already run one instance of the application, then we inform the user about it // and complete the current instance of the application if(is_running) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText("The application is already running.\n" "Allowed to run only one instance of the application."); msgBox.exec(); return -1; } CMainWindow w; w.show(); return a.exec(); } </syntaxhighlight> <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__ [[カテゴリ:Qt]]
Qtの応用 - 多重起動の禁止
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse