QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
}
Описываемая модель обработки сигналов обладает рядом недостатков, считается устаревшей и, более того, как было показано, не обеспечивает надежную обработку сигналов. Тем не менее эту модель достаточно широко применяют в простых случаях, например при необходимости установить тайм-аут для некоторой операции. Вот как, к примеру, устанавливается тайм-аут ожидания установления соединения в TCP/IP-клиенте [9]:
void alarm_handler(int sig) { return; }
int main() {
...
signal(SIGALRM, alarm_handler); alarm(5);
int rc = connect( ... );
alarm(0);
if (rc < 0 && errno == EINTR)
cout << "Истек тайм-аут" << endl, exit(EXIT_FAILURE);
...
}
Здесь уместно напомнить немаловажное обстоятельство, связанное с сигналами, которое обделяется вниманием во многих руководствах по программированию: большинство блокирующих вызовов API (
connect()
delay()
wait()
waitid()
pause()
sigwait()
errno
EINTR
if (delay(100) != 0)
В данном случае учитываем, что функция
delay()
Модель надежных сигналов
В более поздней («новой») модели обработки сигналов (называемой еще моделью надежных сигналов) используются не единичные сигналы, а наборы сигналов — тип
sigset_t
POSIX требует, чтобы в реализации тип
sigset_t
sigset_t
<target_nto.h>
struct { long bits[2]; }
Понятно, что в этом случае тип
sigset_t
Для формирования сигнальных наборов определяется набор специальных операций:
•
sigemptyset(sigset_t *set)
set
•
sigfillset(sigset_t *set)
set
•
sigaddset(sigset_t *set, int signo)
set
signo
•
sigdelset(sigset_t *set, int signo)
set
signo
В качестве
signo
SIGINT
sigset_t sig;
sigemptyset(&sig);
sigaddset(&sig, SIGPOLL);
sigaddset(&sig, SIGALRM);
Этот фрагмент кода формирует сигнальный набор, состоящий из двух сигналов:
SIGPOLL
SIGALRM
Диспозиция обработки каждого сигнала в этой модели устанавливается функцией:
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
где
signo
act
oact
NULL
Структура описания обработчика
sigaction
struct sigaction {
#define sa_handler un._sa_handler
#define sa_sigaction un._sa_sigaction
union {
void (*_sa_handler)(_SIG_ARGS);
void (*_sa_sigaction)(int, siginfo_t*, void*);
} un;
int sa_flags;
sigset_t sa_mask;
};
Это определение по форме, но не по содержанию отличается от описания, показанного в POSIX и используемого во многих традиционных UNIX [5] (обратите внимание на изменение порядка следования полей маски и флагов; это может стать преградой для прямой инициализации структуры в стиле C++ из соображений переносимости):
struct sigaction {
/* указатель на функцию обработчика сигнала */
void (*sa_handler)(int);
/* сигналы, блокирующиеся во время обработки */
sigset_t sa_mask;
/* флаги, влияющие на поведение сигнала */
int sa_flags;
/* указатель на функцию обработчика сигнала */
void (*sa_sigaction)(int, siginfo_t*, void*);
};
Определения
#define
union