Функцию, которая использует глобальную переменную, но завершает работу, следует избегать в обработчиках сигналов?

Изучая кое-что о программировании Unix с помощью C, я узнал, что внутри обработчика сигналов следует избегать функций, которые не могут быть реентерабельными, но если у меня есть что-то вроде:

int main(int argc, char** argv){
     ...
    fileFd=open(...) 
    signal(SIGUSR1, signalHandler)
    ...
}


void signalHandler(int signo){
    switch(signo){

    case SIGUSR1:
        myExit(EXIT_FAILURE);   
        break;

    default: 
        break;

    }
}

Где мой выход

void myExit(int ret){

    ...DO STUFF...
    close(fileFd);
    exit(ret);

}

а fileFd - глобальная переменная, и, если я правильно помню, это делает myExit нереентерабельным... но все еще проблема использовать ее в обработчике сигналов, даже если это вызовет выход из программы? Спасибо, любая помощь приветствуется и извините, если это глупый вопрос.


person cifz    schedule 10.09.2012    source источник
comment
Речь идет не о повторном входе, а о асинхронной безопасности. Выход должен быть в порядке.   -  person Kerrek SB    schedule 10.09.2012
comment
Логично, что нет. Если программа завершается, после выхода не о чем беспокоиться - просто потому, что после выхода ничего нет...   -  person    schedule 10.09.2012


Ответы (3)


Единственное, что вы можете безопасно сделать в обработчике сигнала, это установить переменную volatile sig_atomic_t. Пожалуйста, выполняйте всю свою обработку в основном цикле вашей программы, проверяя, что сигнал был получен (вне обработчика сигнала). Если вам нужно начать делать непереносимые вещи, подумайте хотя бы об использовании _Exit() или _exit(). Некоторые библиотеки C гарантируют, что определенные функции безопасны для сигналов, но очевидно, что это не гарантирует работу в разных системах.

person dmp    schedule 10.09.2012

Может возникнуть проблема в зависимости от "...DO STUFF...". Если то, что там сделано, не может быть сделано дважды (например, освобождение одного и того же указателя), это может привести к сбою.

Однако в вашем конкретном случае это, вероятно, не будет проблемой, если только close(fileFD) влияет на глобальное состояние, а ваш API доступа к файлам позволяет дважды закрывать файлы.

person Jost    schedule 10.09.2012
comment
UNIX close немного опасен - вы не можете безопасно вызывать его дважды с одним и тем же fd, так как fd мог быть повторно использован за это время. - person nneonneo; 10.09.2012

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

Так, например, если прерывание происходит в середине malloc, вызов free в вашем обработчике сигналов (например, для очистки) приведет к взаимоблокировке.

person nneonneo    schedule 10.09.2012
comment
Итак, если у меня есть только функции, безопасные для асинхронных сигналов (на самом деле, я только записываю и закрываю, которые перечислены в сигнале man 7 в списке безопасных для асинхронных сигналов), я в порядке, верно? - person cifz; 10.09.2012