MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの基礎 - プロセスのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの基礎 - プロセス
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == QProcessクラスは、外部プロセスを起動して、それらと通信するためのQtのクラスである。<br> 外部プログラムの実行、入出力の制御、プロセスの状態監視等を行うことができる。<br> <br> QProcessクラスはQIODeviceクラスを継承しているため、標準的なQt入出力機能を利用できる。<br> これにより、readメソッドやwriteメソッド等の操作が可能であり、外部プロセスとのデータのやり取りが容易になる。<br> <br> プロセスの起動方法は、startメソッドを使用する。<br> <syntaxhighlight lang="c++"> QProcess process; process.start("notepad.exe", QStringList()); </syntaxhighlight> <br> プロセスの実行状態は、様々なシグナルを通じて監視することができる。<br> 主要なシグナルとしては、プロセスが開始された時のstartedメソッド、終了した時のfinishedメソッド、エラーが発生した時のerrorOccurredメソッド等がある。<br> <br> 標準入出力とエラー出力の制御も可能である。<br> setStandardOutputProcessメソッドを使用して、あるプロセスの標準出力を別のプロセスの標準入力にパイプすることができる。<br> また、setProcessChannelModeメソッドを使用して、標準出力とエラー出力の扱い方を制御することも可能である。<br> <br> エラーハンドリングでは、<code>error</code>メソッドを使用してエラーの種類を確認することができる。<br> 一般的なエラーとしては、プロセスが見つからない、アクセス権限がない、タイムアウト等がある。<br> <br> プロセスの終了制御も柔軟であり、通常の終了要求である<code>terminate</code>メソッドや強制終了の<code>kill</code>メソッドが用意されている。<br> また、<code>waitForFinished</code>メソッドを使用して、プロセスの終了を待機することもできる。<br> <br> 環境変数の制御も可能で、<code>setEnvironment</code>メソッドや<code>setWorkingDirectory</code>メソッドを使用して、プロセスの実行環境をカスタマイズできる。<br> <br><br> == QProcess::ExitStatus列挙体 == <center> {| class="wikitable" | style="background-color:#fefefe;" |+ QProcess::ExitStatus列挙体 |- ! style="background-color:#66CCFF;" | 指定可能な値 ! style="background-color:#66CCFF;" | 説明 |- | QProcess::NormalExit || * プロセスが正常に終了した場合 * プロセスが自身で終了処理を実行して、正常に完了した状態 <br> 例: 外部コマンドがreturn 0やexit(0)で終了した場合は、exitCodeの値で具体的な終了状態を確認できる。 |- | QProcess::CrashExit || * プロセスが異常終了 (クラッシュ) した場合 * プロセスが予期せず終了した状態 <br> 例: * セグメンテーション違反 * スタックオーバーフロー * 実行時エラーでのクラッシュ * OSによるプロセスの強制終了 * killシグナルによる強制終了 |} </center> <br> これらの状態を監視することにより、外部プロセスの終了の状態 (正常あるいは異常) を判断して、適切なエラーハンドリングを実装することができる。<br> <br> <syntaxhighlight lang="c++"> // 使用例 QObject::connect(process, &QProcess::finished, [=](int exitCode, QProcess::ExitStatus exitStatus) { if (exitStatus == QProcess::NormalExit) { // プロセスが正常に終了した場合 if (exitCode == 0) qDebug() << "プロセスは正常に終了しました"; else qDebug() << "プロセスはエラーコード" << exitCode << "で終了しました"; } else { // QProcess::CrashExit (プロセスがクラッシュした場合) qDebug() << "プロセスがクラッシュしました"; } }); </syntaxhighlight> <br><br> == プロセスの非同期実行 == プロセスを非同期で実行する場合は<code>QProcess::start</code>メソッド、同期して実行する場合は<code>QProcess.execute</code>メソッドを使用する。<br> また、非同期で実行する場合、標準出力や標準エラー出力を取得してウィンドウに表示することもできる。<br> <br> 以下の例は、プロセスを非同期で実行して、プロセスの標準出力と標準エラー出力をウィンドウに表示している。<br> <syntaxhighlight lang="c++"> // MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QProcess> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT private: QProcess m_proc; public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // プロセス用のスロット void ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void UpdateOutput(); void UpdateError(); }; #endif // MAINWINDOW_H </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // MainWindow.cpp #include <QApplication> #include <QProcess> #include "Mainwindow.h" #include "ui_Mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // プロセス用のシグナルとスロットを接続する // Qt 4の記述方法 //QObject::connect(&m_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(UpdateOutput())); //QObject::connect(&m_proc, SIGNAL(readyReadStandardError()), this, SLOT(UpdateError())); //QObject::connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(ProcessFinished(int, QProcess::ExitStatus))); // Qt 5の規約 QObject::connect(&m_proc, &QProcess::readyReadStandardOutput, this, &MainWindow::UpdateOutput); QObject::connect(&m_proc, &QProcess::readyReadStandardError, this, &MainWindow::UpdateError); QObject::connect(&m_proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &MainWindow::ProcessFinished); // Qt 5 (C++14以降) //QObject::connect(&m_proc, qOverload<int, QProcess::ExitStatus >(&QProcess::finished), this, &MainWindow::ProcessFinished); } MainWindow::~MainWindow() { delete ui; } // スロット : 標準出力を表示する void MainWindow::UpdateOutput() { // 標準出力を取得して文字列にする QByteArray output = m_proc.readAllStandardOutput(); QString str = QString::fromLocal8Bit(output); } // スロット : 標準エラー出力を表示する void MainWindow::UpdateError() { // 標準エラー出力を取得して文字列にする QByteArray output = m_proc.readAllStandardError(); QString str = QString::fromLocal8Bit(output); } // スロット : プロセス終了時 void MainWindow::ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { if(exitStatus == QProcess::CrashExit) { QMessageBox::warning(this, tr("Error"), tr("Crashed")); } else if(exitCode != 0) { QMessageBox::warning(this, tr("Error"), tr("Failed")); } else { // 正常終了時の処理 } } // プロセスの起動 void MainWindow::ProcessStart() { QStringList listArgs; listArgs << "<引数1>" << "<引数2>"; m_proc.start("<実行するプログラムのパス>", listArgs); } </syntaxhighlight> <br> また、<code>QProcess</code>クラスの<code>waitForFinished</code>メソッドは、プロセスが終了するまで待機するメソッドである。<br> プロセスが正常に終了した場合は<code>true</code>、そうでない場合(操作のタイムアウト、エラーの発生、既に<code>QProcess</code>のオブジェクトが終了している)は<code>false</code>となる。<br> <syntaxhighlight lang="c++"> QProcess proc; proc.start("/usr/bin/sh" args); bool bStatus = proc.waitForFinished(10 * 1000); // 最大10[s]待機 if (m_proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0) { std::fprintf(stderr, "error : %s", proc.readAllStandardError().constData()); return -1; } </syntaxhighlight> <br><br> == プロセスの同期実行 == 以下の例では、<code>which</code>コマンドを実行して、<code>whoami</code>コマンドが存在しているかどうかを確認している。<br> <br> <syntaxhighlight lang="c++"> #include <QProcess> QProcess process; process.start("which", QStringList() << "whoami"); process.waitForFinished(); // process.exitCode()メソッドの戻り値が0の場合は、whoamiコマンドが存在している // 0以外の戻り値の場合は、whoamiコマンドは存在していない auto iRet = process.exitCode(); </syntaxhighlight> <br> 以下の例では、外部コマンドとして<code>whoami</code>コマンドを実行して、その結果であるユーザ名を取得している。<br> <syntaxhighlight lang="c++"> #include <QProcess> // 現在のユーザ名を取得 QProcess process; process.start("whoami"); process.waitForFinished(); // process.exitCode()メソッドの戻り値が0の場合は、whoamiコマンドが正常に実行されている // 0以外の戻り値の場合は、whoamiコマンドの実行に失敗している if (process.exitCode() == 0) { QString currentUser = QString(process.readAllStandardOutput()).trimmed(); } </syntaxhighlight> <br> 余談ではあるが、Linuxシステムでは、C++の標準ライブラリとPOSIX APIを使用してユーザ名を直接取得することができる。<br> <syntaxhighlight lang="c"> #include <unistd.h> #include <pwd.h> uid_t uid = geteuid(); struct passwd *pw = getpwuid(uid); if (pw) { auto str = QString::fromLocal8Bit(pw->pw_name); } </syntaxhighlight> <br> このアプロ―チの利点として、以下に示すものが挙げられる。<br> * 外部コマンドに依存しないため、whoamiコマンドが利用できないシステムでも動作する。 * プロセスの起動オーバーヘッドがないため、より高速である。 * セキュリティの観点からも、外部コマンドを実行するよりも安全である。 <br> <u>※注意</u><br> * <u>この方法は、POSIX準拠のシステム (Linuxを含む多くのUnixライクシステム) でのみ動作するため、Windowsでは異なるアプローチが必要となる。</u> * unistd.hファイルとpwd.hファイルのヘッダファイルを含める必要がある。<br>これらは標準的なPOSIXヘッダであるが、クロスプラットフォーム開発の場合は注意が必要である。 <br><br> == 切り離されたプロセス == ==== QProcess::startDetachedメソッド ==== Qt 5.10以降、<code>QProcess</code>クラスを使用して、プロセスを切り離して実行できる。<br> <br> <code>start</code>メソッドや<code>execute</code>メソッドでは、プロセスを切り離さずに実行するため、<code>QProcess</code>クラスのデストラクタがプロセスを終了する。<br> これに対して、切り離されたプロセスは、呼び出したプロセスが終了しても影響を受けずに実行し続ける。<br> <br> Linuxでは、切り離されたプロセスは独自のセッションで実行されて、デーモンのように動作する。<br> <br> 切り離されたプロセスを実行するには、<code>QProcess::startDetached</code>メソッドを使用する。<br> なお、<code>QProcess</code>クラスの<code>startDetached</code>メソッドは、静的メソッドであることに注意する。<br> <br> 以下の例では、<code>aplay</code>コマンドを使用して、Sample.wavを再生している。<br> <syntaxhighlight lang="c++"> QProcess::startDetached("aplay Sample.wav"); </syntaxhighlight> <br> 通常のプロセスと同様に、複数の引数と作業ディレクトリを渡すことができる。<br> また、開始されたプロセスの<code>PID</code>を取得することができる。<br> <syntaxhighlight lang="c++"> // プロセスの開始 qint64 pid; QProcess::startDetached("mpg123", {"Sample.mp3", <引数2>, <引数3>, ...}, musicDirPath, &pid); // ...略 </syntaxhighlight> <br> <code>QProcess::startDetached</code>メソッドで取得した<code>PID</code>を使用して、プロセスを<code>kill</code>することもできる。<br> <syntaxhighlight lang="c++"> // プロセスの終了 QProcess::startDetached("kill", {QString::number(pid)}); </syntaxhighlight> <br> 切り離されたプロセスを実行するにあたり、プロセスの出力を制御することもできる。<br> (使用するコマンドの中には、<code>--quiet</code>オプションが存在するものもある)<br> # プロセス環境を設定する。 # <code>stdin</code>、<code>stdout</code>、<code>stderr</code>をファイルにリダイレクトする。 # ネイティブな引数を設定、および、切り離されたプロセス用の<code>CreateProcess</code>関数(Windows API)の引数の設定 <br> ただし、<code>static</code>な<code>startDetached</code>メソッドではなく、<code>非static</code>な<code>QProcess</code>クラスの<code>startDetached</code>メソッドを使用する必要がある。<br> これは、<code>QProcess</code>オブジェクトのプロパティを読み込み、それに応じて切り離されたプロセスを開始する。<br> <br> 以下の例では、<code>mpg123</code>コマンドを使用して、Sample.mp3を再生している。<br> <code>/dev/null</code>へのリダイレクトは、ユーザがオーディオプレーヤの視覚的な出力を非表示にしている。<br> <syntaxhighlight lang="c++"> QProcess process; process.setProgram("mpg123"); process.setArguments({"Sample.mp3"}); process.setWorkingDirectory(musicDirPath); // 例. ファイルが存在するディレクトリのパス(/home/hpge/music等) process.setStandardOutputFile(QProcess::nullDevice()); // /dev/nullへのリダイレクト process.setStandardErrorFile(QProcess::nullDevice()); // /dev/nullへのリダイレクト qint64 pid; process.startDetached(&pid); // ...略 </syntaxhighlight> <br> 以下に、<code>startDetached</code>メソッドでサポートされているサブセットを示す。<br> <u>サブセットを使用する場合、<code>QProcess</code>クラスの他の全てのプロパティは無視されることに注意すること。</u><br> * <code>setArguments</code>メソッド * <code>setCreateProcessArgumentsModifier</code>メソッド * <code>setNativeArguments</code>メソッド * <code>setProcessEnvironment</code>メソッド * <code>setProgram</code>メソッド * <code>setStandardErrorFile</code>メソッド * <code>setStandardInputFile</code>メソッド * <code>setStandardOutputFile</code>メソッド * <code>setWorkingDirectory</code>メソッド <br> ==== プロセスの完了を検知 ==== <code>QProcess::startDetached</code>メソッドを使用した場合、プロセスの完了通知を直接受け取ることはできない。<br> これは、<code>QProcess::startDetached</code>メソッドはデタッチ (切り離し) されたプロセスを起動するため、親プロセス (アプリケーション) との接続が切られるためである。<br> <br> そのため、QProcess::startDetachedメソッドは使用せずに、QProcessクラスのstartメソッドをバッググラウンドで実行する必要がある。<br> <br> <syntaxhighlight lang="c++"> // プロセスを定義 QProcess *process = new QProcess(); process->setProgram("aplay"); process->setArguments(QStringList() << "Sample.wav"); // プロセスを非同期実行 (バックグラウンド) で実行しつつ、完了通知を受け取る QObject::connect(process, &QProcess::finished, [=](int exitCode, QProcess::ExitStatus exitStatus) { process->deleteLater(); // メモリリーク防止 // 何らかの処理 // ...略 }); process->start(); </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // クラス内でシグナル / スロットを定義する場合 (ラムダ式の部分をクラスのメソッドとして記述することも可能) // プロセスを定義 m_Process = new QProcess(this); Process->setProgram("aplay"); m_Process->setArguments(QStringList() << "Sample.wav"); connect(m_Process, &QProcess::finished, this, &SomeClass::someMethod); // SomeClassクラスのsomeMethodメソッド class someClass : public QObject { private: QProcess *m_Process; private: void someMethod(int exitCode, QProcess::ExitStatus exitStatus) { m_Process->deleteLater(); // メモリリーク防止 // 何らかの処理 // ...略 }); } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:Qt]]
Qtの基礎 - プロセス
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse