QNX/UNIX: Анатомия параллелизма
Шрифт:
Здесь удобный случай показать разницу между обработкой сигналов на базе очереди и простой обработкой (модель надежных сигналов). Для этого заменим две строки заполнения структуры
а заголовок функции
Сколько бы раз мы ни повторяли тестирование, идентификатор потока, получающего и обрабатывающего сигнал, всегда будет равен 4.Что же происходит:
• главный поток (TID = 1) создает 3 новых потока (TID = 2, 3, 4);
• главный поток переходит в пассивное ожидание сигналов, но в его маске доставка посылаемого сигнала (41) заблокирована;
• выполнение функции потока начинается с разблокирования ожидаемого сигнала;
• … 3 потока (TID = 2, 3, 4) ожидают поступления сигнала;
• при поступлении серии сигналов вся их очередь доставляется и обрабатывается одним потоком с TID = 4, который тут же в цикле возвращается к ожиданию следующих сигналов.
Таким образом, сигнал доставляется одному и только одному потоку, который не блокирует этот сигнал. Обработчик сигнала вызывается в контексте (стек, области собственных данных) этого потока. После выполнения обработчика сигнал поглощается. Какому из потоков, находящихся в состоянии блокирования в ожидании сигналов (в масках которых разблокирован данный сигнал), будет доставлен экземпляр сигнала, предсказать невозможно; это так и должно быть исходя из общих принципов диспетчеризации потоков. Но реально этим потоком является поток, последнимперешедший в состояние ожидания. Для того чтобы убедиться в этом, заменим предпоследнюю строку программы (
Теперь у нас 4 равнозначных потока, ожидающих прихода сигнала, переходящих в состояние ожидания в последовательности: TID = 2, 3, 4, 1. Реакция процесса на приход сигнала изменится на:
Изменим текст функции потока на ( файл s7.cc):
Поведение приложения радикально изменится — происходит смена обрабатывающего потока (чтобы сократить объем вывода, серии посылаемых сигналов состоят из одного сигнала). Следует отметить, что смена обрабатывающего потока происходит между сериями, но ни в коем случае не внутри длинных серий, что можно проследить экспериментально.
Такая модель вряд ли может быть названа в полной мере «сигналами в потоках», так как сигнал в ней в конечном итоге направляется процессу как контейнеру, содержащему потоки (можно сказать и так: в оболочку адресного пространства процесса). И только после этого в контексте одного из потоков(и в случае множественных потоков, разблокированных на обработку единого сигнала, невозможно предсказать, в контексте какого из них) выполняется обработчик сигнала. Главный поток процесса (TID = 1) в этой схеме участвует в равнозначном качестве (здесь хорошо видно, что устоявшееся понятие «реакция процесса на сигнал» в строгом смысле некорректно).
Перейдем к более конкретным вопросам: как можно продуктивно использовать эту схему в многопоточных приложениях? Рассмотрим сначала случай, когда каждый из рабочих потоков разблокирован на получение одного, свойственного только ему сигнала ( файл s9.cc):