QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
В качестве примера работы вызова
spawn*()
exec()
• Родительский процесс ( p1) порождает дочерний ( p1ch) и ожидает от него поступления сигнала
SIGUSR1
• Дочерний процесс периодически посылает родителю сигнал
SIGUSR1
• Родительский процесс может переустановить (с помощью параметров командной строки запуска) для дочернего: период посылки сигнала (1-й параметр задан в нашем приложении константой) и приоритет, с которым будет выполняться дочерний процесс (2-й параметр, в качестве которого ретранслируется единственный параметр команды запуска родителя).
В данный момент нас интересует только то приложение, в котором дочерний процесс порождается вызовом
spawnl()
Итак, родительское приложение ( файл p1.cc):
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>
#include <signal.h>
#include <unistd.h>
#include <sched.h>
// обработчик сигнала
static void handler(int signo, siginfo_t* info, void* context) {
int oldprio = getprio(0);
setprio(0, info->si_value, sival_int);
cout << "SIG = " << signo << " old priority = "
<< oldprio << " new priority = " << getprio(0) << endl;
setprio(0, oldprio);
}
int main(int argc, char* argv[]) {
// установить обработчик сигнала
sigset_t sig;
sigemptyset(&sig);
//определение #define SIGUSR1 16
sigaddset(&sig, SIGUSR1);
sigprocmask(SIG_BLOCK, &sig, NULL);
struct sigaction act;
act.sa_mask = sig;
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGUSR1, &act, NULL) < 0)
perror("set signal handler"), exit(EXIT_FAILURE);
// создать новый (дочерний) процесс
const char* prg = "./p1ch", *sdelay = "3";
pid_t pid =
((argc > 1 ) && (atoi(argv[1]) >= sched_get_priority_min(SCHED_RR)) &&
(atoi(argv[1]) <= sched_get_priority_max(SCHED_RR))) ?
spawnl(P_NOWAIT, prg, prg, sdelay, argv[1], NULL) :
spawnl(P_NOWAIT, prg, prg, sdelay, NULL);
if (pid == -1)
perror("spawn child process"), exit(EXIT_FAILURE);
// размаскировать и ожидать сигнала.
sigprocmask(SIG_UNBLOCK, &sig, NULL);
while (true) {
if (sleep(3) != 0) continue;
cout << "parent main loop: priority = " << getprio(0) << endl;
}
}
Дочернее приложение ( файл p1ch.cc), которое и будет запускать показанный выше родительский процесс:
#include <stdio.h>
#include <iostream.h>
#include <sched.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *argv[]) {
int val, del = 5;
if ((argc > 1) &&
(sscanf(argv[1], "%i", &val) == 1) && (val > 0)) del = val;
if ((argc > 2) &&
(sscanf(argv[2], "%i", &val) == 1 ) && (val > 0) &&
(val <= sched_get_priority_max(SCHED_RR)))
if (setprio(0, val) == -1) perror("set priority");
// периодически уведомлять родителя SIGUSR1, используя
// его как сигнал реального времени (с очередью):
while(true) {
sleep(del);
union sigval val;
val.sival_int = getprio(0);
// #define SIGUSR1 16
sigqueue(getppid(), SIGUSR1, val);
}