Unix pthreads и сигналы: для обработчиков сигналов streamа

У меня возникли проблемы с получением streamов, чтобы поймать правильные сигналы.

Например,

Сначала я начинаю основной stream (tid 1).

Затем он устанавливает обработчик сигнала для SIGUSR1 в SIGUSR1 (), используя signal(2) .

Основной stream создает новый stream, с tid 2.

В streamе 2 я регистрирую обработчик сигнала для SIGUSR1 для SIGUSR1 function2() используя signal(2) .

Затем stream 1 создает stream 3 (tid 3).

Из streamа 3 я использую pthread_kill(1, SIGUSR1) для отправки сигнала в stream 1.

Однако function2() вызывается, а не function1() .

Является ли это поведение предполагаемым, или есть что-то, что мне нужно изменить, чтобы заставить эти обработчики сигналов работать?

Изменить: я немного отлаживал, и получается, что сигнал IS отправляется в stream 1, однако function2() почему-то вызывается из streamа 1. Есть ли обходной путь для этого?

    В дополнение к ответу алка :

    Вы можете использовать указатель функции для streamа, чтобы выбрать, какая функция будет выполняться, когда определенный сигнал будет доставлен, по streamу.

    Примечание. Сигналы доставляются в любой stream, который явно не блокирует его доставку. Это не меняет этого. Вам все равно нужно использовать pthread_kill() или подобные механизмы, чтобы направлять сигнал в конкретный stream; сигналы, которые поднимаются или отправляются процессу (вместо конкретного streamа), по-прежнему будут обрабатываться случайным streamом (среди тех, которые его не блокируют).

    Я не могу придумать какой-либо прецедент, когда я лично предпочел бы такой подход; до сих пор всегда был какой-то другой способ, что-то еще легче и лучше. Итак, если вы планируете внедрить что-то подобное для реального приложения, пожалуйста, отстранитесь и пересмотрите свою логику приложения.

    Но, поскольку техника возможна , вот как я могу ее реализовать:

     #include  /* Per-thread signal handler function pointer. * Always use set_thread_SIG_handler() to change this. */ static __thread void (*thread_SIG_handler)(int, siginfo_t *, void *) = (void *)0; /* Process-wide signal handler. */ static void process_SIG_handler(int signum, siginfo_t *info, void *context) { void (*func)(int, siginfo_t *, void *); #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) func = __atomic_load_n(&thread_SIG_handler, __ATOMIC_SEQ_CST); #else func = __sync_fetch_and_add(&thread_SIG_handler, (void *)0); #endif if (func) func(signum, info, context); } /* Helper function to set new per-thread signal handler */ static void set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *)) { #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) __atomic_store_n(&thread_SIG_handler, func, __ATOMIC_SEQ_CST); #else void (*oldfunc)(int, siginfo_t *, void *); do { oldfunc = thread_SIG_handler; } while (!__sync_bool_compare_and_swap(&thread_SIG_handler, oldfunc, func)); #endif } /* Install the process-wide signal handler. */ int install_SIG_handlers(const int signum) { struct sigaction act; sigemptyset(&act.sa_mask); act.sa_sigaction = process_SIG_handler; act.sa_flags = SA_SIGACTION; if (sigaction(signum, &act, NULL)) return errno; return 0; } 

    Мне нравится выше, потому что он не требует pthreads и очень надежный и надежный. Помимо визуального беспорядка из-за того, что логика препроцессора выбирает, какой стиль атомных встроенных модhive используется, это тоже очень просто, если вы внимательно посмотрите на него.

    GCC 4.7 и более поздние версии предоставляют C ++ 11-подобные __атомные встроенные модули , более старые версии GCC и другие компиляторы (ICC, Pathscale, Portland Group) предоставляют встроенные встроенные функции __sync . __thread слово __thread для локального хранилища streamов также должно быть доступно во всех существующих системах POSIX-y.

    Если у вас есть архаичная система или настаивайте на соблюдении стандартов, следующий код должен иметь примерно эквивалентное поведение:

     #include  #include  #include  static pthread_key_t thread_SIG_handler_key; static void process_SIG_handler(int signum, siginfo_t *info, void *context) { void (*func)(int, siginfo_t *, void *); *((void **)&func) = pthread_getspecific(thread_SIG_handler_key); if (func) func(signum, info, context); } static int set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *)) { sigset_t block, old; int result; sigemptyset(&block); sigaddset(&block, SIG); /* Use signal number instead of SIG! */ result = pthread_sigmask(SIG_BLOCK, &block, &old); if (result) return errno = result; result = pthread_setspecific(thread_SIG_handler_key, (void *)func); if (result) { pthread_sigmask(SIG_SETMASK, &old, NULL); return errno = result; } result = pthread_sigmask(SIG_SETMASK, &old, NULL); if (result) return errno = result; return 0; } int install_SIG_handlers(const int signum) { struct sigaction act; int result; result = pthread_key_create(&thread_SIG_handler_key, NULL); if (result) return errno = result; sigemptyset(&act.sa_mask); act.sa_sigaction = process_SIG_handler; act.sa_flags = SA_SIGACTION; if (sigaction(signum, &act, NULL)) return errno; return 0; } 

    Я думаю, что ближайший реальный эквивалент кода, подобный этому, который я когда-либо использовал, – это тот, где я использовал один сигнал реального времени ( SIGRTMIN+0 ), заблокированный во всех, кроме одного streamа, в качестве отражателя: он отправил другой сигнал в реальном времени ( SIGRTMIN+1 ) для ряда рабочих streamов, чтобы прервать блокировку ввода-вывода. (Это можно сделать с помощью одного сигнала в реальном времени, но модель с двумя сигналами проще реализовать и упростить для поддержания.)

    Такое reflection сигнала или разветвление иногда полезно, и это не отличается от этого подхода. Разные достаточно, чтобы оправдать свой собственный вопрос, хотя, если кто-то заинтересован.

    Невозможно установить обработчики сигналов «per-thread».

    Из man 7 signal (выделение мной):

    Распознавание сигнала является атрибутом для каждого процесса : в многопоточном приложении расположение конкретного сигнала одинаково для всех streamов.

    Тем не менее , можно направить каждый тип сигнала на другой stream, замаскировав прием любого количества типов сигналов на основе «на streamе».

    О том, как направить набор сигнальных типов на конкретный stream, вы могли бы взглянуть на этот ответ: https://stackoverflow.com/a/20728819/694576