Предоставление / передача аргумента в обработчик сигнала - PullRequest
54 голосов
/ 07 августа 2011

Могу ли я предоставить / передать какие-либо аргументы обработчику сигнала?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

Теперь обработчик выглядит так:

void signal_handler(int signo) {
    /* some code */
}

Если я хочу сделать что-то особенное, то есть удалить временные файлы, могу ли я предоставить эти файлы в качестве аргумента этому обработчику?

Редактировать 0: Спасибо за ответы. Мы обычно избегаем / не рекомендуем использовать глобальные переменные. И в этом случае, если у вас огромная программа, что-то может пойти не так в разных местах, и вам, возможно, придется много чего делать. Почему API был разработан таким образом?

Ответы [ 6 ]

51 голосов
/ 07 августа 2011

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

Ответ на редактирование 0: Исторические причины. Сигналы - это действительно старый и очень низкоуровневый дизайн. По сути, вы просто дали ядру один адрес для некоторого машинного кода и попросили его перейти на этот конкретный адрес, если произойдет то или иное. Мы вернулись к мышлению «переносимого ассемблера», где ядра предоставляют базовый сервис без излишеств, и, что бы ни предполагалось для пользовательского процесса, он должен делать сам.

Кроме того, обычные аргументы против глобальных переменных здесь не применяются. Обработчик сигнала сам по себе является глобальной настройкой, поэтому отсутствует соответствующая возможность иметь несколько различных наборов пользовательских параметров для него. (Ну, на самом деле, он не полностью глобален, а только глобален для потоков. Но API потоков будет включать в себя некоторый механизм локального хранения потоков, который в данном случае вам нужен).

16 голосов
/ 07 августа 2011

Регистрация обработчика сигнала уже является глобальным состоянием , эквивалентным глобальным переменным. Так что не стоит оскорблять использование глобальных переменных для передачи аргументов. Однако это огромная ошибка (почти наверняка неопределенное поведение , если вы не эксперт!) В любом случае делать что-либо из обработчика сигнала. Если вместо этого вы просто блокируете сигналы и опрашиваете их из основного цикла программы, вы можете избежать всех этих проблем.

6 голосов
/ 13 апреля 2017

Это действительно старый вопрос, но я думаю, что могу показать вам хороший трюк, который бы ответил на вашу проблему. Нет необходимости использовать sigqueue или что-то еще.

Мне также не нравится использование глобальных переменных, поэтому мне пришлось найти умный способ, в моем случае, отправить пустую ptr (которую вы позже можете привести к тому, что вам нужно).

На самом деле вы можете сделать это:

signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc

Тогда ваш sighandler будет выглядеть так:

int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !

Вы можете спросить: как тогда получить * ptr?

Вот как: При инициализации

signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);

В твоем оцепенении func :

int sighandler(const int signal, void *ptr)
{
  static my_struct saved = NULL;

  if (saved == NULL)
     saved = ptr;
  if (signal == SIGNALWHATEVER)
     // DO YOUR STUFF OR FREE YOUR PTR
   return (0);
}
4 голосов
/ 12 января 2016

Абсолютно. Вы можете передавать целые числа и указатели в обработчики сигналов, используя sigqueue () вместо обычного kill ().

http://man7.org/linux/man-pages/man2/sigqueue.2.html

1 голос
/ 07 августа 2011

Сохраните имена файлов в глобальной переменной, а затем получите доступ к ней из обработчика.Обратному вызову обработчика сигнала будет передан только один аргумент: идентификатор фактического сигнала, вызвавшего проблему (например, SIGINT, SIGTSTP)

Редактировать 0: «Должна быть веская причина, по которой нельзя разрешать аргументыобработчик «.<- существует вектор прерывания (в основном, набор адресов перехода к подпрограммам для каждого возможного сигнала).Учитывая способ запуска прерывания на основе вектора прерывания, вызывается определенная функция.К сожалению, неясно, где будет вызываться память, связанная с переменной, и в зависимости от прерывания эта память может быть действительно повреждена.Есть способ обойти это, но тогда вы не можете использовать существующую инструкцию сборки int 0x80 (которую все еще используют некоторые системы) </p>

0 голосов
/ 25 апреля 2012

Вы можете использовать обработчик сигнала, который является методом класса. Затем этот обработчик может получить доступ к данным члена из этого класса. Я не совсем уверен, что Python делает под прикрытием вокруг вызова C signal (), но это должно быть изменение области данных?

Я был поражен, что это работает, но это работает. Запустите это и затем убейте процесс из другого терминала.

import os, signal, time

class someclass:
    def __init__(self):
        self.myvalue = "something initialized not globally defined"
        signal.signal(signal.SIGTERM, self.myHandler)
    def myHandler(self, s, f):
        # WTF u can do this?
        print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue


print "Making an object"
a = someclass()

while 1:
    print "sleeping.  Kill me now."
    time.sleep(60)
...