Обробка сигналів з декількох потоків в Linux


119

Що в Linux відбувається, коли програма (яка, можливо, має кілька потоків) отримує сигнал, як SIGTERM або SIGHUP?

Яка нитка перехоплює сигнал? Чи може кілька потоків отримати один і той же сигнал? Чи є спеціальна нитка, повністю присвячена обробці сигналів? Якщо ні, що відбувається всередині потоку, який повинен обробляти сигнал? Як виконується виконання після закінчення розпорядження обробника сигналу?

Відповіді:


35

Це трохи нюанс, виходячи з версії ядра Linux, яку ви використовуєте.

Якщо припустити 2.6 потокові позиції, і якщо ви говорите про OS, що надсилає SIGTERM або SIGHUP, сигнал надсилається на обробку, яка приймається і обробляється кореневою ниткою. Використовуючи потоки POSIX, ви також можете надсилати SIGTERM до окремих потоків, але я підозрюю, що ви запитуєте про те, що відбувається, коли ОС передає сигнал в процес.

У 2.6, SIGTERM призведе до того, що дочірні нитки вийдуть "чисто", де, як 2.4, дочірні нитки залишилися у невизначеному стані.


А що відбувається всередині кореневої нитки, коли приймається сигнал? Скажімо, я написав спеціальний обробник сигналу для SIGUSR1, і тепер я надсилаю цей сигнал в процес. Кореневий потік отримає цей сигнал. Можливо, це посеред якоїсь функції в цей момент. Що буде?

1
якщо у вас є налаштування обробника, це буде розглядатися як переривання, і потік програми припиниться, і ваш власний обробник буде виконаний. Після його виконання контроль повернеться, припускаючи, що ви нічого не зробили для зміни нормального потоку (вихід тощо).
— Алан

Зауважте, що це характерно для SIGUSR1, який IIRC не перериває системні виклики. Якщо ви спробували це, наприклад, з SIGINT, це може перервати зчитування потоку, і коли ви повернетесь до читання, потік може повернути помилку, що вона була перервана.
— Алан

10
Я трохи розгублений щодо того, що розуміється під "кореневою ниткою". Чи означає це, що обробник для SIGTERM завжди працюватиме в основному потоці, або він може працювати в будь-якому потоці?
— Стівен Натт

3
Ця відповідь , яка зазначає, що для обробки сигналу обрана довільна нитка, суперечить вашій відповіді.
— користувач202729

135

pthreads(7) описує, що POSIX.1 вимагає всіх потоків в атрибутах спільного використання процесу, включаючи:

  • диспозиції сигналів

POSIX.1 також вимагає відзначити деякі атрибути для кожного потоку, включаючи:

У complete_signalрутині ядра Linux є наступний блок коду - коментарі є досить корисними:

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

Отже, ви бачите, що ви відповідаєте за те, куди подаються сигнали:

Якщо ваш процес встановив диспозицію сигналу до SIG_IGNабо SIG_DFL, то сигнал ігнорується (або за замовчуванням - вбити, ядро ​​чи ігнорувати) для всіх потоків.

Якщо ваш процес встановив розпорядження сигналу певним розпорядником обробника, то ви можете контролювати, який потік буде приймати сигнали, маніпулюючи конкретними масками сигналу потоку за допомогою pthread_sigmask(3). Ви можете призначити один потік для управління всіма ними, або створити один потік на сигнал, або будь-яку суміш цих параметрів для конкретних сигналів, або ви покладаєтесь на поточну поведінку ядра Linux за замовчуванням для доставки сигналу в основний потік.

Однак деякі сигнали є спеціальними відповідно до signal(7)сторінки людини:

Сигнал може генеруватися (і, таким чином, очікувати) для процесу в цілому (наприклад, при надсиланні за допомогою kill (2) ) або для конкретної потоку (наприклад, певних сигналів, таких як SIGSEGV і SIGFPE, генерованих як наслідок виконання конкретна інструкція машинної мови спрямована на потоки, як і сигнали, спрямовані на певний потік, використовуючи pthread_kill (3) ). Сигнал, орієнтований на процес, може бути доставлений до будь-якої з потоків, яка наразі не блокує сигнал. Якщо більше ніж один з потоків має сигнал розблокований, то ядро ​​вибирає довільну нитку, до якої доставити сигнал.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.