Spec-Zone.ru › C++

std::signal

Определено в заголовке <csignal>
/*signal-handler*/* signal( int sig, /*signal-handler*/* handler );
(1)
extern "C" using /*signal-handler*/ = void(int);
(2) (только для пояснения*)

Изменяет обработку сигнала sig. В зависимости от значения handler сигнал можно игнорировать, установить для него обработчик по умолчанию или обработать с помощью пользовательской функции, вызываемой как (*handler)(sig).

Если для сигнала задана функция-обработчик и сигнал возникает, реализация определяет, будет ли std::signal(sig, SIG_DFL) выполнено непосредственно перед началом работы обработчика сигнала. Кроме того, реализация может предотвращать возникновение некоторого определяемого реализацией набора сигналов во время работы обработчика сигнала.

Для некоторых сигналов реализация может вызвать std::signal(sig, SIG_IGN) при запуске программы. Для остальных реализация должна вызвать std::signal(sig, SIG_DFL).

(Примечание: POSIX ввёл sigaction для стандартизации этих определяемых реализацией особенностей поведения.)

Параметры

sig - сигнал, для которого задаётся обработчик. Может принимать определяемое реализацией значение или одно из следующих значений:
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
определяет типы сигналов
(макроконстанта)
handler - обработчик сигнала. Это должно быть одно из следующих значений:
  • SIG_DFL макрос. Для сигнала задаётся обработчик по умолчанию.
  • SIG_IGN макрос. Сигнал игнорируется.
  • Указатель на функцию. Сигнатура функции должна быть эквивалентна следующей:
extern "C" void fun(int sig);

Возвращаемое значение

Предыдущий обработчик сигнала в случае успеха или SIG_ERR в случае ошибки (в некоторых реализациях установка обработчика сигнала может быть отключена).

Обработчик сигнала

На пользовательскую функцию, установленную в качестве обработчика сигнала, накладываются следующие ограничения.

Если обработчик сигнала вызван НЕ в результате std::abort или std::raise (асинхронный сигнал), поведение не определено, если

  • обработчик сигнала вызывает любую функцию стандартной библиотеки, кроме
    • std::abort
    • std::_Exit
    • std::quick_exit
    • std::signal, если первый аргумент — номер обрабатываемого в данный момент сигнала (асинхронный обработчик может повторно зарегистрировать себя, но не другие сигналы).
  • обработчик сигнала обращается к любому объекту со статической длительностью хранения, который не является std::atomic или (начиная с C++11)volatilestd::sig_atomic_t.
(до C++17)

Обычная свободная от блокировок атомарная операция — это вызов функции f из <atomic> или <stdatomic.h>(начиная с C++23), для которого выполняются следующие условия:

  • f является функцией std::atomic_is_lock_free,
  • f является методом-членом is_lock_free (например, std::atomic::is_lock_free()),
  • f является нестатическим методом-членом std::atomic_flag,
  • f является нешаблонной функцией, а первый параметр f имеет тип cv std::atomic_flag*,
  • f является нестатическим методом-членом, вызванным для объекта obj, таким образом, что obj.is_lock_free() даёт true, или
  • f является нешаблонной функцией, и для каждого аргумента-указателя на атомарный объект arg, переданного в f, std::atomic_is_lock_free(arg) даёт true.

Поведение не определено, если обработчик сигнала выполняет любое из следующих действий:

  • вызывает любую библиотечную функцию, кроме обычных свободных от блокировок атомарных операций и следующих безопасных для сигналов функций (обратите особое внимание: динамическое выделение памяти небезопасно для сигналов):
    • std::signal, если первый аргумент — номер обрабатываемого в данный момент сигнала (обработчик сигнала может повторно зарегистрировать себя, но не другие сигналы).
    • методы-члены std::numeric_limits
    • std::_Exit
    • std::abort
    • std::quick_exit
    • методы-члены std::initializer_list и перегрузки std::initializer_list функций std::begin и std::end
    • std::forward, std::move, std::move_if_noexcept
    • все функции из <type_traits>
    • std::memcpy и std::memmove
  • обращается к объекту с потоковой длительностью хранения
  • вычисляет выражение dynamic_cast
  • вычисляет выражение throw
  • входит в блок try block
  • инициализирует статическую переменную, выполняя динамическую инициализацию вне локальной области (в том числе отложенную до первого ODR-использования)
  • ожидает завершения инициализации любой переменной со статической длительностью хранения, если другой поток одновременно выполняет её инициализацию
(начиная с C++17)

Если пользовательская функция возвращает управление при обработке SIGFPE, SIGILL, SIGSEGV или любого другого определяемого реализацией сигнала, указывающего на вычислительное исключение, поведение не определено.

Если обработчик сигнала вызван в результате std::abort или std::raise (синхронный сигнал), поведение не определено, если обработчик сигнала вызывает std::raise.

При входе в обработчик сигнала состояние среды вычислений с плавающей точкой и значения всех объектов не определены, за исключением

  • объектов типа volatilestd::sig_atomic_t
  • объектов свободных от блокировок типов std::atomic
  • побочных эффектов, ставших видимыми через std::atomic_signal_fence
(начиная с C++11)

При возврате из обработчика сигнала значение любого изменённого им объекта, который не является volatilestd::sig_atomic_t или свободным от блокировок std::atomic, является неопределённым.

(до C++14)

Вызов функции signal() синхронизируется с каждым соответствующим вызовом обработчика сигнала.

Если обработчик сигнала выполняется в результате вызова std::raise (синхронно), выполнение обработчика упорядочено перед вызовом std::raise и упорядочено после возврата из него; обработчик выполняется в том же потоке, что и std::raise. Выполнение обработчиков других сигналов не упорядочено относительно остальной части программы и происходит в неопределённом потоке.

Два обращения к одному и тому же объекту типа volatilestd::sig_atomic_t не приводят к гонке данных, если оба происходят в одном потоке, даже если одно или несколько обращений выполняются в обработчике сигнала. Для каждого вызова обработчика сигнала вычисления, выполняемые потоком, вызвавшим обработчик, можно разделить на две группы A и B так, чтобы ни одно вычисление из B не предшествовало по отношению happens-before вычислениям из A, а вычисления таких объектов volatilestd::sig_atomic_t принимали значения так, как если бы все вычисления в A предшествовали по отношению happens-before выполнению обработчика сигнала, а выполнение обработчика сигнала предшествовало по отношению happens-before всем вычислениям в 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

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
    • 17.13.5 Обработчики сигналов [support.signal]
  • Стандарт C++20 (ISO/IEC 14882:2020):
    • 17.13.5 Обработчики сигналов [support.signal]
  • Стандарт C++17 (ISO/IEC 14882:2017):
    • 21.10.4 Обработчики сигналов [support.signal]

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

Отчёт об ошибке Применён к Опубликованное поведение Правильное поведение
LWG 3756 C++17 не было ясно, является ли std::atomic_flag безопасным для сигналов является

См. также

raise
вызывает обработчик указанного сигнала
(функция)
atomic_signal_fence
(C++11)
барьер между потоком и обработчиком сигнала, выполняемым в том же потоке
(функция)
Документация C для signal

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/utility/program/signal

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API