2017-01-09 9 views
2

Рассмотрим следующую тестовую программуSIGINT сброса обработчика в Visual C++ 2015

#include <csignal> 
#include <iostream> 

volatile std::sig_atomic_t signal_raised = 0; 

void set_signal_raised(int signal) { 
    signal_raised = 1; 
} 

void check(std::sig_atomic_t expected) { 
    if (signal_raised != expected) { 
     std::cerr << signal_raised << " != " << expected << std::endl; 
     abort(); 
    } 
} 

int main() { 
    using namespace std; 
    check(0); 
    std::signal(SIGINT, set_signal_raised); 
    check(0); 
    std::raise(SIGINT); 
    check(1); 
    signal_raised = 0; 
    check(0); 
    std::raise(SIGINT); 
    check(1); 
    cerr << "OK.\n"; 
} 

С GCC и Clang, он выводит "OK". Однако с Visual Studio 2015 он ничего не выводит.

Обработчик сигнала сбрасывается после обработки первого сигнала. Это можно проверить, добавив

auto prev = std::signal(SIGINT, set_signal_raised); 
if (prev != set_signal_raised) { 
    std::cerr << "Unexpected handler." << std::endl; 
    abort(); 
} 

к функции проверки. Это разрешено и ожидается?

+0

Я не могу увидеть что-нибудь в С11, позволяя поведение VS в. Тем не менее, это не исключает возможности его запретить. –

ответ

1

Сброс расположения сигнала - это поведение, которое использовала система Unix System V. Но BSD (в настоящее время glibc) не сбрасывает расположение сигнала. Любое поведение разрешено стандартом POSIX. C не указывает, разрешен ли сброс.

От signal(2):

POSIX.1 решена Портативность беспорядок, указав sigaction (2), который обеспечивает явный контроль семантики, когда обработчик сигнала вызывается; используйте этот интерфейс вместо сигнала().

В оригинальных системах UNIX, когда обработчик, который был установлен с помощью сигнала() была вызвана доставкой сигнала, то расположения сигнала будет сбрасываются в SIG_DFL, и система не блокировать доставку дополнительных экземпляров сигнала. Это значение эквивалентно вызывающему сигмату (2) со следующими флагами:

sa.sa_flags = SA_RESETHAND | SA_NODEFER;

Система V также предоставляет эту семантику для сигнала(). Это было плохо , потому что сигнал может быть доставлен снова до того, как у обработчика был шанс вернуть его обратно. Более того, быстрые поставки такого же сигнала могут привести к рекурсивным вызовам обработчика.

Итак, кажется, Visual studio следует за поведением системы V.

Это разрешено и ожидается?

Разрешено, но не обязательно. По этой причине POSIX представил sigaction(). Если у вас есть sigaction(), то используйте его. В противном случае, вам просто нужно переустановить каждый раз обработчик внутри обработчика сигнала:

void set_signal_raised(int signal) { 
    std::signal(SIGINT, set_signal_raised); 
    signal_raised = 1; 
} 
+0

Отлично! Просто, чтобы быть понятным для всех, кто читает это в будущем: переустановка текущего сигнала разрешена в обработчиках. (В общем, почти ничего не разрешено в обработчиках.) Http://en.cppreference.com/w/cpp/utility/program/signal – Petter