Жанры книг
Мы в соц.сетях
ParaKnig📚 » Компьютеры и Интернет » Интернет » QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович
<< На главную

QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович

Читать онлайн QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 46 47 48 49 50 51 52 53 54 ... 106
Перейти на страницу:

# k6 -p214005 -s41 -n100

направляет процессу с PID = 214005 последовательность из 100 сигналов с кодом 41 ( SIGRTMIN). Посылая нашему процессу-тестеру последовательность из N сигналов, мы получим N сообщений вида:

SIG = 41; TID = 4

Примечание

Здесь удобный случай показать разницу между обработкой сигналов на базе очереди и простой обработкой (модель надежных сигналов). Для этого заменим две строки заполнения структуры sigactionна:

act.sa_handler = handler;

act.sa_flags = 0;

а заголовок функции handler()перепишем так: static void handler(int signo). Если теперь мы в точности повторим предыдущий тест, то при посылке процессу- тестеру последовательности из N сигналов мы получим всего одно сообщение все того же вида. Это наблюдение интересно еще и тем, что оно показывает, что алгоритм взаимодействия сигнала с потоками не зависит от того, какая обработка установлена для этого сигнала: на основе модели сигналов реального времени или на основе модели надежных сигналов.

Сколько бы раз мы ни повторяли тестирование, идентификатор потока, получающего и обрабатывающего сигнал, всегда будет равен 4.Что же происходит:

• главный поток (TID = 1) создает 3 новых потока (TID = 2, 3, 4);

• главный поток переходит в пассивное ожидание сигналов, но в его маске доставка посылаемого сигнала (41) заблокирована;

• выполнение функции потока начинается с разблокирования ожидаемого сигнала;

• … 3 потока (TID = 2, 3, 4) ожидают поступления сигнала;

• при поступлении серии сигналов вся их очередь доставляется и обрабатывается одним потоком с TID = 4, который тут же в цикле возвращается к ожиданию следующих сигналов.

Таким образом, сигнал доставляется одному и только одному потоку, который не блокирует этот сигнал. Обработчик сигнала вызывается в контексте (стек, области собственных данных) этого потока. После выполнения обработчика сигнал поглощается. Какому из потоков, находящихся в состоянии блокирования в ожидании сигналов (в масках которых разблокирован данный сигнал), будет доставлен экземпляр сигнала, предсказать невозможно; это так и должно быть исходя из общих принципов диспетчеризации потоков. Но реально этим потоком является поток, последнимперешедший в состояние ожидания. Для того чтобы убедиться в этом, заменим предпоследнюю строку программы ( pause();) на:

threadfunc(NULL);

Теперь у нас 4 равнозначных потока, ожидающих прихода сигнала, переходящих в состояние ожидания в последовательности: TID = 2, 3, 4, 1. Реакция процесса на приход сигнала изменится на:

SIG = 41, TID = 1

Изменим текст функции потока на ( файл s7.cc):

void* threadfunc(void* data) {

 while (true) {

  SignalProcmask(0, 0, SIG_UNBLOCK, &amp;sig, NULL);

  delay(1);

  SignalProcmask(0, 0, SIG_BLOCK, &amp;sig, NULL);

  delay(10);

 }

}

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

SIG = 41, TID = 1

SIG = 41; TID = 4

SIG = 41; TID = 4

SIG = 41; TID = 1

SIG = 41; TID = 1

SIG = 41; TID = 4

SIG = 41; TID = 4

SIG = 41; TID = 1

SIG = 41; TID = 2

SIG = 41; TID = 2

SIG = 41; TID = 3

SIG = 41; TID = 4

Такая модель вряд ли может быть названа в полной мере «сигналами в потоках», так как сигнал в ней в конечном итоге направляется процессу как контейнеру, содержащему потоки (можно сказать и так: в оболочку адресного пространства процесса). И только после этого в контексте одного из потоков(и в случае множественных потоков, разблокированных на обработку единого сигнала, невозможно предсказать, в контексте какого из них) выполняется обработчик сигнала. Главный поток процесса (TID = 1) в этой схеме участвует в равнозначном качестве (здесь хорошо видно, что устоявшееся понятие «реакция процесса на сигнал» в строгом смысле некорректно).

Перейдем к более конкретным вопросам: как можно продуктивно использовать эту схему в многопоточных приложениях? Рассмотрим сначала случай, когда каждый из рабочих потоков разблокирован на получение одного, свойственного только ему сигнала ( файл s9.cc):

Чередование потоковых сигналов

#include &lt;stdio.h&gt;

#include &lt;iostream.h&gt;

#include &lt;signal.h&gt;

#include &lt;unistd.h&gt;

#include &lt;pthread.h&gt;

#include &lt;time.h&gt;

#include &lt;sys/neutrino.h&gt;

static void handler(int signo, siginfo_t* info, void* context) {

 cout &lt;&lt; &quot;SIG = &quot; &lt;&lt; signo &lt;&lt; &quot;; TID = &quot; &lt;&lt; pthread_self() &lt;&lt; endl;

}

void* threadfunc(void* data) {

 // блокировать реакцию на все сигналы

 sigset_t sig;

 sigfillset(&amp;sig);

 SignalProcmask(0, 0, SIG_BLOCK, &amp;sig, NULL);

 // разблокировать реакцию на свой сигнал

 sigemptyset(&amp;sig);

 sigaddset(&amp;sig, (int)data);

 SignalProcmask(0, 0, SIG_UNBLOCK, &amp;sig, NULL);

 // цикл ожидания приходящих сигналов

 while (true) pause();

}

int main() {

1 ... 46 47 48 49 50 51 52 53 54 ... 106
Перейти на страницу:
На этой странице вы можете бесплатно читать книгу QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович бесплатно.
Комментарии
Открыть боковую панель
Комментарии
Лариса
Лариса 11.03.2026 - 20:17
Странно,здесь имя девочки Аграфена,а на других сайтах я прослушала три книги этого цикла с именем Дарвина.Зачем менять имя и путать читателей? Опечатка- не Дарвина,  а  Дарина.
Григорий
Григорий 09.04.2025 - 22:24
Лучшая книга всех времен
Женя
Женя 02.04.2025 - 16:08
Любимая книга