C++教科書/標準ライブラリ編/<csignal>の章

編集

概要

編集

<csignal>ヘッダーはプログラムにおけるシグナル処理を行うための機能を提供します。シグナルとは、特定の事象が発生したことをオペレーティングシステムからプロセスに通知するために使われるメカニズムです。代表的なシグナルには、割り込み(SIGINT)、セグメンテーション違反(SIGSEGV)、算術演算例外(SIGFPE)などがあります。

  • sig_atomic_t

シグナルハンドラ内で安全にアクセスできる最小のロックフリー型です。この型への参照は、シグナルハンドラが呼び出される間は常に代入可能です。

マクロ

編集
シグナル種別マクロ
SIGABRT
異常終了シグナル
SIGFPE
算術演算例外が発生したことを示す
SIGILL
無効命令が実行されたことを示す
SIGINT
端末からの割り込みを示す
SIGSEGV
無効なメモリ参照を示す
SIGTERM
終了要求を示す
シグナルハンドラ指定用マクロ
SIG_DFL
デフォルトの動作を行う
SIG_IGN
シグナルを無視する

関数

編集
signal(int sig, sig_handler func)
指定のシグナル(sig)が発生した際に呼び出されるハンドラ関数(func)を設定します。funcにSIG_DFLを渡すとデフォルトの動作に、SIG_IGNを渡すと無視するように設定できます。正常場合は以前のハンドラを返し、エラー時はSIG_ERRを返します。
raise(int sig)
指定のシグナル(sig)を発生させ、現在設定されているハンドラを呼び出します。

シグナルハンドラの作成

編集

シグナルハンドラは以下のプロトタイプを持つ関数として実装します。

void handler(int sig) {
   // ハンドラ処理
}

ハンドラ内では、シグナルセーフでない関数(malloc、printf、exit等)の呼び出しは避ける必要があります。また、グローバル変数へのアクセスにも注意が必要です。sig_atomic_t型の変数を介して安全にグローバル状態にアクセスできます。

実践例

編集
割り込みハンドラの実装
#include <csignal>
#include <cstdio>

volatile sig_atomic_t gSignalStatus;

void handler(int sig) { gSignalStatus = sig; }

auto main() -> int {
    gSignalStatus = 0;
    signal(SIGINT, handler);

    // 処理ループ
    while (gSignalStatus != SIGINT) {
        std::puts("Running...");
        // 処理
    }

    std::puts("Interrupted!");
    return 0;
}
シグナルを使った並列化
#include <csignal>
#include <cstdio>

volatile sig_atomic_t gCounter;

void handler(int /*unused*/) { ++gCounter; }

auto main() -> int {
    gCounter = 0;
    signal(SIGINT, handler);  // 割り込みハンドラ設定

    // 並列処理のためにSIGINTを発生
    for (int i = 0; i < 1000000; ++i) {
        raise(SIGINT);
    }

    std::puts("gCounter = {}", gCounter);
    return 0;
}

まとめ

編集

<csignal>ヘッダーはシグナルハンドリング機能を提供し、プログラムの例外処理や並列化、割り込み処理などに利用できます。シグナルセーフな実装に注意が必要ですが、C++プログラムをさまざまな環境で安全かつ効率的に動作させるための重要な機能です。