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

249
38

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


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

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


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

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


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

спросил(а) 2011-08-07T04:56:00+04:00 9 лет, 1 месяц назад
1
Решение
269

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


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

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

ответил(а) 2011-08-07T05:00:00+04:00 9 лет, 1 месяц назад
145

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

ответил(а) 2011-08-07T05:49:00+04:00 9 лет, 1 месяц назад
57

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


Мне также не нравится использование переменных глобалов, поэтому я должен был найти умный способ, в моем случае, отправить void 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);

В вашей функции sighandler
 


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);
}

ответил(а) 2017-04-13T22:20:00+03:00 3 года, 5 месяцев назад
57

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


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

ответил(а) 2011-08-07T05:02:00+04:00 9 лет, 1 месяц назад
41

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


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

ответил(а) 2016-01-12T08:58:00+03:00 4 года, 8 месяцев назад
41

Вы можете использовать обработчик сигнала, который является методом класса. Затем этот обработчик может получить доступ к данным элемента из этого класса. Я не совсем уверен, что 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)

ответил(а) 2012-04-25T18:43:00+04:00 8 лет, 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема