Читаем QNX/UNIX: Анатомия параллелизма полностью

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

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

#include

#include

#include

#include

#include

#include

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

 cout << "SIG = " << signo << "; TID = " << pthread_self << endl;

}

void* threadfunc(void* data) {

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

 sigset_t sig;

 sigfillset(&sig);

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

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

 sigemptyset(&sig);

 sigaddset(&sig, (int)data);

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

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

 while (true) pause;

}

int main {

 // для обработки всей группы сигналов управления потоками используем

 // единую функцию реакции, иначе все было бы гораздо проще.

 struct sigaction act;

 sigemptyset(&act.sa_mask);

 act.sa_sigaction = handler;

 act.sa_flags = SA_SIGINFO;

 // создаем группу однотипных потоков

 const int thrnum = 3;

 for (int i = SIGRTMIN; i - SIGRTMIN < thrnum; i++) {

  sigset_t sig;

  sigemptyset(&sig);

  sigaddset(&sig, 1);

  // нам нужно, чтобы главный поток не реагировал:

  sigprocmask(SIG_BLOCK, &sig, NULL);

  if (sigaction(i, &act, NULL) < 0) perror("set signal handler: ");

  // для передачи номера сигнала используется

  // трюк с подменой типа параметра:

  pthread_create(NULL, NULL, threadfunc, (void*)(i));

 }

 // начинаем циклическую синхронизацию потоков.

 for (int i = 0; ; i++) {

  sleep(1);

  // посылку сигнала можно (так даже будет корректнее)

  // сделать так:

  // union sigval val;

  // val.sival_int = i;

  // sigqueue(getpid, SIGRTMIN + i % thrnum, val);

  // но мы сознательно демонстрируем и приемлемость kill:

  kill(getpid, SIGRTMIN + i % thrnum);

 }

}

В этой программе главный поток циклически по таймеру активизирует поочередно каждый поток. Вот фрагмент вывода работающей программы:

SIG = 41; TID = 2

SIG = 42; TID = 3

SIG = 43; TID = 4

SIG = 41; TID = 2

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT