名前空間
変種
操作

std::signal

提供: cppreference.com
< cpp‎ | utility‎ | program
 
 
 
プログラムサポートユーティリティ
プログラム終了
(C++11)
(C++11)
環境との通信
シグナル
シグナルの種類
非ローカルジャンプ
 
ヘッダ <csignal> で定義
/*signal-handler*/* signal(int sig, /*signal-handler*/* handler);
(1)
extern "C" using /*signal-handler*/ = void(int); // exposition-only
(2)

シグナル sig のためのハンドラを設定します。 シグナルハンドラは、デフォルトの処理を行う、シグナルを無視する、またはユーザ定義の関数が呼ばれるように設定することができます。

シグナルハンドラが関数に設定され、シグナルが発生したとき、シグナルハンドラの開始直前に std::signal(sig, SIG_DFL) が実行されるかどうかは処理系定義です。 また処理系は、シグナルハンドラを実行している間、処理系定義のシグナルの集合が発生しないように防ぐかもしれません。

いくつかのシグナルについては、処理系はプログラム開始時に std::signal(sig, SIG_IGN) を呼んでも構いません。 その他のシグナルについては、処理系は std::signal(sig, SIG_DFL) を呼ばなければなりません。

(ノート: POSIX はこれらの処理系定義の動作を標準化するための sigaction を導入しました)

目次

[編集] 引数

sig - シグナルハンドラを設定するシグナル。 処理系定義の値、または以下の値のいずれか。
シグナルの種類を定義します
(マクロ定数) [edit]


handler - シグナルハンドラ。 以下のいずれかでなければなりません。
  • SIG_DFL マクロ。 シグナルハンドラはデフォルトのシグナルハンドラに設定されます。
  • SIG_IGN マクロ。 シグナルは無視されます。
  • 関数へのポインタ。 関数のシグネチャは以下と同等でなければなりません。
extern "C" void fun(int sig);

[編集] 戻り値

成功した場合は以前のシグナルハンドラ、失敗した場合は SIG_ERR (処理系によってはシグナルハンドラの設定は無効化されていることがあります)。

[編集] シグナルハンドラ

シグナルハンドラとしてインストールされるユーザ定義の関数には、以下の制限が課されます。

std::abort または std::raise の結果としてではなくシグナルハンドラが呼ばれた場合 (非同期シグナル)、以下は未定義動作となります。

  • シグナルハンドラが標準ライブラリ内の何らかの関数を呼ぶ。 ただし以下を除きます。
  • std::abort
  • std::_Exit
  • std::quick_exit
  • 現在処理中のシグナル番号を第1引数に指定した std::signal (非同期ハンドラは自分自身を再登録することができますが、他のシグナルはできません)。
  • シグナルハンドラが std::atomic または (C++11およびそれ以降) volatile std::sig_atomic_t 以外の静的またはスレッドローカル (C++11およびそれ以降)記憶域期間を持つあらゆるオブジェクトを参照する。
(C++17以前)

任意のシグナルハンドラが以下のいずれかを行った場合、動作は未定義です。

  • 以下のシグナルセーフな関数以外の、何らかのライブラリ関数を呼ぶ (特に、動的確保はシグナルセーフではないことに注意してください)
  • スレッド記憶域期間を持つオブジェクトへのアクセス
  • dynamic_cast
  • throw
  • try ブロックに入る。 関数 try ブロックも含みます。
  • 動的非ローカル初期化を行う静的変数の初期化 (最初の ODR 使用まで遅延されているものも含みます)
  • 別のスレッドが並行的に初期化している静的記憶域期間の任意の変数の初期化の完了を待つ
(C++17およびそれ以降)

SIGFPE, SIGILL, SIGSEGV またはその他の計算上の例外を表す処理系定義のシグナルを処理するとき、ユーザ定義の関数が戻ると、動作は未定義です。

std::abort または std::raise の結果としてシグナルハンドラが呼ばれた場合 (同期シグナル)、シグナルハンドラが std::raise を呼ぶと、動作は未定義です。

シグナルハンドラの開始時、以下を除くすべてのオブジェクトの値および浮動小数点数環境の状態は未規定です。

(C++11およびそれ以降)

シグナルハンドラから戻るとき、 volatile std::sig_atomic_t またはロックフリーな std::atomic 以外の、シグナルハンドラで変更されたあらゆるオブジェクトの値は、不定になります。

(C++14以前)

関数 signal() の呼び出しは、あらゆるシグナルハンドラの呼び出しの結果に対して同期します。

std::raise の呼び出しの結果としてシグナルハンドラが (同期的に) 実行された場合、そのハンドラの実行は、 std::raise の呼び出しに対して後続配列され、その戻りに先行配列され、 std::raise と同じスレッドで実行されます。 他のシグナルに対するハンドラの実行は、プログラムの残りに対して配列されず、未規定のスレッドで実行されます。

volatile std::sig_atomic_t 型の同じオブジェクトへの2つのアクセスは、両方が同じスレッドで行われれば、シグナルハンドラ内で行われても、データ競合を発生しません。 シグナルハンドラの各呼び出しについて、シグナルハンドラを呼び出すスレッドで行われる評価は、 A 内の評価に対して先行発生する評価が B になく、 そのような volatile std::sig_atomic_t オブジェクトの評価がシグナルハンドラの実行に対して先行発生する A 内のすべての評価を通して値を取得し、シグナルハンドラの実行が B 内のすべての評価に対して先行発生するような、2つのグループ A と B に分割できます。

(C++14およびそれ以降)

[編集] ノート

POSIX は、 signal がスレッドセーフであることを要求しており、任意のシグナルハンドラから呼ぶことができる非同期シグナルセーフなライブラリ関数の一覧を規定しています

シグナルハンドラは、 C リンケージを持ち、一般的に、 C と C++ の共通のサブセットの機能のみを使用すると期待されています。 C++ リンケージを持つ関数がシグナルハンドラとして使用できるかどうかは処理系定義です。

[編集]

#include <csignal>
#include <iostream>
 
namespace
{
  volatile std::sig_atomic_t gSignalStatus;
}
 
void signal_handler(int signal)
{
  gSignalStatus = signal;
}
 
int main()
{
  // Install a signal handler
  std::signal(SIGINT, signal_handler);
 
  std::cout << "SignalValue: " << gSignalStatus << '\n';
  std::cout << "Sending signal " << SIGINT << '\n';
  std::raise(SIGINT);
  std::cout << "SignalValue: " << gSignalStatus << '\n';
}

出力例:

SignalValue: 0
Sending signal 2
SignalValue: 2

[編集] 関連項目

特定のシグナルに対するシグナルハンドラを実行します
(関数) [edit]
同じスレッドで実行されるシグナルハンドラとの間のフェンス
(関数) [edit]