MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の応用 - シグナルのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の応用 - シグナル
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == シグナル (Signal) は、Unix系オペレーティングシステム (Linux含む) において、プロセスに対して非同期的にイベントを通知するための仕組みである。<br> シグナルは、プロセス間通信 (IPC) の一種として分類されるが、他のIPC機構と比較して、情報量が限定的である点が特徴である。<br> <br> シグナルは、以下に示すような状況で使用される。<br> * カーネルからプロセスへの通知 *: 例 : 不正なメモリアクセス、ゼロ除算等の例外 * ユーザからプロセスへの制御 *: 例 : [Ctrl] + [C]キーによる割り込み、killコマンドによる終了要求 * プロセス間の通知 *: 例 : 子プロセスの終了通知、タイマの満了通知 <br> シグナルは、POSIXで標準化されており、移植性の高いプログラミングが可能である。<br> ただし、Linuxでは、POSIXで定義されていない独自のシグナルや拡張機能も提供されている。<br> <br> C++でシグナルを扱う場合、C言語のAPIをそのまま使用することができるが、モダンC++の機能を活用することにより、より安全で保守性の高いソースコードを記述することができる。<br> <br><br> == シグナルの種類 == Linuxでは、多数のシグナルが定義されており、それぞれ異なる意味と用途を持つ。<br> 下表に、主要なシグナルを示す。<br> <br> <center> <br> {| class="wikitable" |- ! シグナル名 !! 番号 !! デフォルト動作 !! 説明 |- | SIGHUP || 1 || 終了 || ハングアップ検出、制御端末のクローズ、またはプロセスの死 |- | SIGINT || 2 || 終了 || キーボードからの割り込み (通常はCtrl+C) |- | SIGQUIT || 3 || 終了+コアダンプ || キーボードからの終了シグナル (通常はCtrl+\) |- | SIGILL || 4 || 終了+コアダンプ || 不正な命令 |- | SIGABRT || 6 || 終了+コアダンプ || abort()関数からの中止シグナル |- | SIGFPE || 8 || 終了+コアダンプ || 浮動小数点例外 |- | SIGKILL || 9 || 終了 || 強制終了 (キャッチ不可) |- | SIGSEGV || 11 || 終了+コアダンプ || 不正なメモリ参照 |- | SIGPIPE || 13 || 終了 || パイプ破壊: 読み手のないパイプへの書き込み |- | SIGALRM || 14 || 終了 || alarm()からのタイマーシグナル |- | SIGTERM || 15 || 終了 || 終了シグナル |- | SIGUSR1 || 10 || 終了 || ユーザ定義シグナル1 |- | SIGUSR2 || 12 || 終了 || ユーザ定義シグナル2 |- | SIGCHLD || 17 || 無視 || 子プロセスの停止または終了 |- | SIGCONT || 18 || 継続 || 停止していれば継続 |- | SIGSTOP || 19 || 停止 || プロセスの停止 (キャッチ不可) |- | SIGTSTP || 20 || 停止 || 端末で入力された停止 (通常はCtrl+Z) |} </center> <br> <u>※注意</u><br> <u>SIGKILL と SIGSTOPは、キャッチ、ブロック、または無視することができない。</u><br> <u>これらは、システムがプロセスを確実に制御するために予約されているためである。</u><br> <br><br> == signal関数 == 基本的なシグナルハンドラの登録方法は、signal関数を使用する方法である。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <unistd.h> // シグナルハンドラ関数 // シグナルハンドラは、シグナル番号を引数として受け取る void signalHandler(int signum) { std::cout << "Interrupt signal (" << signum << ") received." << std::endl; // プログラムを終了 exit(signum); } int main() { // SIGINTシグナル ([Ctrl] + [C]キー) に対してハンドラを登録 signal(SIGINT, signalHandler); std::cout << "Press [Ctrl] + [C] to trigger signal handler." << std::endl; // 無限ループで待機 while(true) { std::cout << "Running..." << std::endl; sleep(1); } return 0; } </syntaxhighlight> <br> <u>ただし、signal関数の動作は、POSIXで完全に標準化されておらず、システムによって微妙に異なる場合がある。</u><br> <u>このため、移植性の高いソースコードを記述する場合は、<code>sigaction</code>関数の使用が推奨される。</u><br> <br><br> == sigaction関数 == sigaction関数は、signal関数よりも詳細な制御が可能で、POSIXで完全に標準化されている。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <cstring> #include <unistd.h> // シグナルハンドラ関数 void signalHandler(int signum, siginfo_t* info, void* context) { std::cout << "Signal " << signum << " received from process " << info->si_pid << std::endl; } int main() { struct sigaction sa; // sigaction構造体の初期化 std::memset(&sa, 0, sizeof(sa)); // シグナルハンドラを設定 sa.sa_sigaction = signalHandler; // SA_SIGINFOフラグを設定して、拡張情報を取得 sa.sa_flags = SA_SIGINFO; // SIGINTに対してハンドラを登録 if (sigaction(SIGINT, &sa, nullptr) == -1) { std::cerr << "Error setting up signal handler" << std::endl; return 1; } std::cout << "Press [Ctrl] + [C] to trigger signal handler." << std::endl; // 無限ループで待機 while(true) { std::cout << "Running..." << std::endl; sleep(1); } return 0; } </syntaxhighlight> <br> <center> {| class="wikitable" |+ sigaction構造体の主要なメンバ |- ! メンバ名 !! 説明 |- | sa_handler || 従来型のシグナルハンドラ関数へのポインタ |- | sa_sigaction || 拡張情報を受け取るシグナルハンドラ関数へのポインタ |- | sa_mask || ハンドラ実行中にブロックするシグナルのマスク |- | sa_flags || シグナル処理の動作を制御するフラグ |} </center> <br> <center> {| class="wikitable" |+ 主要なフラグ (sa_flags) |- ! フラグ名 !! 説明 |- | SA_SIGINFO || 拡張情報を含むハンドラ (sa_sigaction) を使用 |- | SA_RESTART || 一部のシステムコールを自動的に再開 |- | SA_NOCLDSTOP || 子プロセスが停止したときにSIGCHLDを生成しない |- | SA_NOCLDWAIT || 子プロセスの終了時にゾンビプロセスを作成しない |- | SA_NODEFER || ハンドラ実行中に同じシグナルをブロックしない |- | SA_RESETHAND || ハンドラ実行後にシグナルの動作をデフォルトに戻す |} </center> <br><br> == C++でのシグナル処理 == ==== std::signal ==== C++11以降では、std::signal関数が標準ライブラリに含まれている。<br> これは、C言語のsignal関数のラッパーである。<br> <br> 以下の例では、std::atomicを使用してシグナルハンドラとメインスレッド間で安全にフラグを共有している。<br> シグナルハンドラ内では、複雑な処理を避け、アトミック変数の設定のみを行うことが推奨される。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <atomic> #include <thread> #include <chrono> // グローバルなアトミック変数でシグナル受信を管理 std::atomic<bool> signalReceived(false); void signalHandler(int signum) { signalReceived.store(true); } int main() { // シグナルハンドラを登録 std::signal(SIGINT, signalHandler); std::signal(SIGTERM, signalHandler); std::cout << "Running... Press Ctrl+C to stop." << std::endl; // メインループ while (!signalReceived.load()) { std::cout << "Working..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } std::cout << "Signal received. Cleaning up..." << std::endl; return 0; } </syntaxhighlight> <br> ==== signalfd関数を使用した同期的なシグナル処理 ==== Linuxでは、signalfdシステムコールを使用して、シグナルをファイルディスクリプタ経由で処理することができる。<br> これにより、select関数、poll関数、epoll関数等の多重化機構と統合することが可能になる。<br> <br> signalfd関数を使用するメリットは、以下の通りである。<br> * シグナルを同期的に処理できる。 * 複数のイベントソース (ファイル、ソケット、シグナル等) を統一的に処理できる。 * 非同期シグナル安全性の問題を回避できる。 <br> <syntaxhighlight lang="c++"> #include <iostream> #include <sys/signalfd.h> #include <signal.h> #include <unistd.h> #include <cstring> int main() { sigset_t mask; int sfd; struct signalfd_siginfo fdsi; ssize_t s; // SIGINTとSIGTERMをマスクに追加 sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); // これらのシグナルをブロック // signalfd関数は、ブロックされたシグナルのみを処理できる if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) { std::cerr << "sigprocmask error" << std::endl; return 1; } // signalfd関数でファイルディスクリプタを作成 sfd = signalfd(-1, &mask, 0); if (sfd == -1) { std::cerr << "signalfd error" << std::endl; return 1; } std::cout << "Waiting for signals... Press Ctrl+C to trigger." << std::endl; // メインループ while (true) { // シグナルを待機 s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); if (s != sizeof(struct signalfd_siginfo)) { std::cerr << "read error" << std::endl; break; } // 受信したシグナルを処理 if (fdsi.ssi_signo == SIGINT) { std::cout << "Got SIGINT" << std::endl; break; } else if (fdsi.ssi_signo == SIGTERM) { std::cout << "Got SIGTERM" << std::endl; break; } else { std::cout << "Read unexpected signal" << std::endl; } } close(sfd); return 0; } </syntaxhighlight> <br><br> == シグナルマスクの操作 == シグナルマスクは、プロセスがどのシグナルをブロックするかを制御する。<br> ブロックされたシグナルは、配信が保留され、ブロックが解除されるまで処理されない。<br> <br> sigprocmask関数の第1引数で指定できる操作を以下に示す。<br> * SIG_BLOCK *: 指定されたシグナルを現在のマスクに追加 * SIG_UNBLOCK *: 指定されたシグナルを現在のマスクから削除 * SIG_SETMASK *: シグナルマスクを指定されたセットで置き換え <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <unistd.h> #include <cstring> void criticalSection() { sigset_t newmask, oldmask; // 新しいシグナルマスクを作成 sigemptyset(&newmask); sigaddset(&newmask, SIGINT); sigaddset(&newmask, SIGTERM); // シグナルをブロックし、古いマスクを保存 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) { std::cerr << "sigprocmask error" << std::endl; return; } std::cout << "Critical section: signals blocked" << std::endl; // クリティカルセクション for (int i = 0; i < 5; i++) { std::cout << "Working in critical section... " << i << std::endl; sleep(1); } std::cout << "Critical section done" << std::endl; // 元のシグナルマスクを復元 if (sigprocmask(SIG_SETMASK, &oldmask, nullptr) == -1) { std::cerr << "sigprocmask restore error" << std::endl; } } void signalHandler(int signum) { std::cout << "Signal " << signum << " received" << std::endl; } int main() { // シグナルハンドラを登録 signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); std::cout << "Before critical section - signals are not blocked" << std::endl; sleep(3); criticalSection(); std::cout << "After critical section - signals are unblocked again" << std::endl; sleep(3); return 0; } </syntaxhighlight> <br><br> == タイマシグナルの使用 == シグナルを使用して、アラームやタイマ機能を定義することができる。<br> <br> ==== alarm関数を使用した単純なタイマ ==== <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <unistd.h> void alarmHandler(int signum) { std::cout << "Timer expired!" << std::endl; } int main() { // SIGALRMハンドラを登録 signal(SIGALRM, alarmHandler); std::cout << "Setting alarm for 5 seconds..." << std::endl; // 5秒後にSIGALRMを送信 alarm(5); std::cout << "Waiting..." << std::endl; // タイマを待機 pause(); // シグナルを受信するまで待機 std::cout << "Done" << std::endl; return 0; } </syntaxhighlight> <br> ==== setitimer関数を使用した周期的なタイマ ==== setitimer関数では、3種類のタイマを指定することができる。<br> <br> * ITIMER_REAL *: 実時間で計測し、SIGALRMを送信 * ITIMER_VIRTUAL *: プロセスのユーザ時間で計測し、SIGVTALRMを送信 * ITIMER_PROF *: プロセスのユーザ時間とシステム時間の合計で計測し、SIGPROFを送信 <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <sys/time.h> #include <unistd.h> volatile int timerCount = 0; void timerHandler(int signum) { timerCount++; std::cout << "Timer fired: " << timerCount << std::endl; } int main() { struct itimerval timer; // SIGALRMハンドラを登録 signal(SIGALRM, timerHandler); // 最初のタイマ満了時間を設定 (2秒後) timer.it_value.tv_sec = 2; timer.it_value.tv_usec = 0; // タイマの周期を設定 (1秒ごと) timer.it_interval.tv_sec = 1; timer.it_interval.tv_usec = 0; // タイマを開始 if (setitimer(ITIMER_REAL, &timer, nullptr) == -1) { std::cerr << "Error setting timer" << std::endl; return 1; } std::cout << "Timer started. Will fire 10 times." << std::endl; // タイマイベントが10回実行するまで待機 while (timerCount < 10) { sleep(1); } // タイマを停止 timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &timer, nullptr); std::cout << "Timer stopped" << std::endl; return 0; } </syntaxhighlight> <br><br> == 子プロセスの終了処理 == 子プロセスが終了すると、親プロセスにSIGCHLDシグナルが送信される。<br> これを適切に処理することで、ゾンビプロセスの発生を防ぐことができる。<br> <br> waitpid関数のオプションを以下に示す。<br> * WNOHANG *: 終了した子プロセスがない場合、ブロックせずに即座に戻る * WUNTRACED *: 停止した子プロセスの状態も返す * WCONTINUED *: 再開した子プロセスの状態も返す <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <sys/wait.h> #include <unistd.h> #include <cstring> void sigchldHandler(int signum) { int status; pid_t pid; // 全ての終了した子プロセスを回収 // WAITNOHANGを指定することで、ノンブロッキングで処理 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status)) { std::cout << "Child process " << pid << " exited with status " << WEXITSTATUS(status) << std::endl; } else if (WIFSIGNALED(status)) { std::cout << "Child process " << pid << " killed by signal " << WTERMSIG(status) << std::endl; } } } int main() { struct sigaction sa; // sigaction構造体の初期化 std::memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigchldHandler; // SA_RESTARTフラグを設定して、システムコールを自動再開 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; // SIGCHLDハンドラを登録 if (sigaction(SIGCHLD, &sa, nullptr) == -1) { std::cerr << "sigaction error" << std::endl; return 1; } std::cout << "Creating child processes..." << std::endl; // 3つの子プロセスを作成 for (int i = 0; i < 3; i++) { pid_t pid = fork(); if (pid == -1) { std::cerr << "fork error" << std::endl; return 1; } else if (pid == 0) { // 子プロセス std::cout << "Child process " << getpid() << " started" << std::endl; sleep(i + 1); // 異なる時間だけスリープ std::cout << "Child process " << getpid() << " exiting" << std::endl; exit(i); } } // 親プロセス std::cout << "Parent process waiting for children..." << std::endl; // 全ての子プロセスが終了するまで待機 sleep(5); std::cout << "Parent process done" << std::endl; return 0; } </syntaxhighlight> <br><br> == 非同期シグナル安全性 == シグナルハンドラ内では、非同期シグナル安全 (async-signal-safe) な関数のみを呼び出すことができる。<br> これは、シグナルハンドラが、プログラムの任意の時点で実行される可能性があるためである。<br> <br> 非同期シグナル安全な関数の例を以下に示す。<br> * write関数 * _exit関数 * signal関数 * sigaction関数 * kill関数 * getpid関数 <br> 非同期シグナル安全でない関数の例を以下に示す。<br> * printf関数 / std::cout *: 内部でロックを使用している * malloc関数 / new *: メモリアロケータが非再入可能 * pthread関数 *: 多くのpthread関数が非再入可能 <br> sig_atomic_t型は、シグナルハンドラとの間で安全に値を交換できることが保証された整数型である。<br> ただし、volatileキーワードを付加することにより、コンパイラの最適化を防ぐ必要がある。<br> <br> 以下の例では、安全にシグナルハンドラを定義している。<br> <syntaxhighlight lang="c++"> #include <unistd.h> #include <csignal> #include <cstring> // グローバルフラグ (volatileとして宣言) volatile sig_atomic_t signalFlag = 0; void signalHandler(int signum) { // sig_atomic_t型の変数への代入は安全 signalFlag = 1; // write関数は非同期シグナル安全 const char msg[] = "Signal received\n"; write(STDOUT_FILENO, msg, sizeof(msg) - 1); } int main() { signal(SIGINT, signalHandler); while (!signalFlag) { // メインループ sleep(1); } // シグナルフラグがセットされたら、メインプログラムで処理 // ここでは非同期シグナル安全でない関数を使用できる // std::cout等の使用が可能 return 0; } </syntaxhighlight> <br><br> == リアルタイムシグナル == POSIXリアルタイムシグナルは、従来のシグナルに対する拡張機能である。<br> Linuxでは、SIGRTMIN から SIGRTMAX までの範囲のシグナル番号が、リアルタイムシグナルとして使用できる。<br> <br> リアルタイムシグナルの特徴を以下に示す。<br> * キューイング *: 複数の同じシグナルがキューに入る * 優先順位 *: シグナル番号の小さいものから順に配信される * データ送信 *: シグナルと共に整数値やポインタを送信できる <br> sigqueue関数は、リアルタイムシグナルを送信するために使用される。<br> これにより、シグナルと共にデータを送信することができる。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <unistd.h> #include <cstring> void realtimeSignalHandler(int signum, siginfo_t* info, void* context) { std::cout << "Received real-time signal " << signum << std::endl; std::cout << "Value: " << info->si_value.sival_int << std::endl; std::cout << "From PID: " << info->si_pid << std::endl; } int main() { struct sigaction sa; // sigaction構造体の初期化 std::memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = realtimeSignalHandler; sa.sa_flags = SA_SIGINFO; // リアルタイムシグナルのハンドラを登録 int rtsig = SIGRTMIN + 5; if (sigaction(rtsig, &sa, nullptr) == -1) { std::cerr << "sigaction error" << std::endl; return 1; } std::cout << "Real-time signal handler registered for signal " << rtsig << std::endl; // 自分自身にシグナルを送信 union sigval value; value.sival_int = 42; if (sigqueue(getpid(), rtsig, value) == -1) { std::cerr << "sigqueue error" << std::endl; return 1; } // シグナルを待機 sleep(1); return 0; } </syntaxhighlight> <br><br> == RAIIパターンを使用したシグナルマスク管理 == 現代のC++では、RAIIパターンを使用して、シグナルマスクの管理を自動化することができる。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <csignal> #include <unistd.h> // シグナルマスクを管理するRAIIクラス class SignalMaskGuard { private: sigset_t oldmask_; bool valid_; public: // コンストラクタでシグナルをブロック SignalMaskGuard(const sigset_t& mask) : valid_(false) { if (sigprocmask(SIG_BLOCK, &mask, &oldmask_) == 0) { valid_ = true; } } // デストラクタで元のマスクを復元 ~SignalMaskGuard() { if (valid_) { sigprocmask(SIG_SETMASK, &oldmask_, nullptr); } } // コピー禁止 SignalMaskGuard(const SignalMaskGuard&) = delete; SignalMaskGuard& operator=(const SignalMaskGuard&) = delete; }; void criticalSection() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); // スコープを抜けると自動的にマスクが復元される SignalMaskGuard guard(mask); std::cout << "In critical section - signals blocked" << std::endl; sleep(3); std::cout << "Leaving critical section" << std::endl; } void signalHandler(int signum) { std::cout << "Signal " << signum << " received" << std::endl; } int main() { signal(SIGINT, signalHandler); std::cout << "Before critical section" << std::endl; sleep(2); criticalSection(); std::cout << "After critical section - signals unblocked" << std::endl; sleep(2); return 0; } </syntaxhighlight> <br><br> == その他 == ==== シグナルハンドラの定義 ==== * シグナルハンドラは可能な限り単純に記述する。 *: フラグを設定するだけの最小限の処理が推奨される。 * 非同期シグナル安全な関数のみを使用する。 *: printf関数、malloc関数等は使用してはならない。 * グローバル変数を使用する場合は、<code>sig_atomic_t</code> 型 と <code>volatile</code> 修飾子を使用する。 *: これにより、アトミックな操作とコンパイラの最適化防止が保証される。 <br> ==== シグナルマスクの管理 ==== * クリティカルセクションでは、必要なシグナルをブロックする。 *: 重要な処理中に割り込まれないようにする。 * sigprocmask関数の戻り値を必ず確認する。 *: エラーが発生した場合の処理を適切に行う。 * RAIIパターンを使用して、マスクの復元を自動化する。 *: スコープを抜ける際に、確実に元のマスクに戻す。 <br> ==== 子プロセスの管理 ==== * SIGCHLDハンドラを必ず実装する。 *: ゾンビプロセスの発生を防ぐ。 * waitpid関数をループで呼び出す。 *: 複数の子プロセスが同時に終了する可能性がある。 * WNOHANGオプションを使用する。 *: ハンドラ内でブロックしないようにする。 <br> ==== エラーハンドリング ==== * 全てのシステムコールの戻り値を確認する。 *: エラーが発生した場合の処理を実装する。 * errnoを適切に処理する。 *: システムコールのエラー原因を特定する。 <br> ==== マルチスレッド環境 ==== * シグナルマスクはスレッドごとに独立している。 *: 各スレッドで適切にマスクを設定する必要がある。 * <code>pthread_sigmask</code> 関数を使用する。 *: マルチスレッドプログラムでは、<code>sigprocmask</code>関数 ではなく <code>pthread_sigmask</code> 関数を使用する。 * シグナルを特定のスレッドで処理する設計を検討する。 *: 専用のシグナルハンドリングスレッドを作成する方法もある。 <br><br> == CMakeを使用したビルド設定 == シグナル処理を使用するプログラムのCMakeLists.txtファイルの設定例を以下に示す。<br> <br> <syntaxhighlight lang="cmake"> cmake_minimum_required(VERSION 3.16) project(<任意のプロジェクト名>) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # ...略 # 実行可能ファイルの作成 add_executable(<任意の実行可能ファイル名> # ...略 ) # システムライブラリのリンク # 通常、特別なライブラリは不要 # リアルタイム拡張を使用する場合のみ -lrt が必要な場合がある if(UNIX AND NOT APPLE) target_link_libraries(<任意の実行可能ファイル名> PRIVATE rt) endif() </syntaxhighlight> <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Signal,Linux Signal,C++,Signal Handler,POSIX,IPC,Process Communication,Async,Real-time Signal,シグナル,シグナルハンドラ,プロセス間通信,非同期 |description={{PAGENAME}} - LinuxのC++向けシグナル処理に関する詳細な情報 | This page is {{PAGENAME}} in our wiki about Linux signal handling in C++ |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:C++]]
C++の応用 - シグナル
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse