Обробка сигналів з декількох потоків в 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.