QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
pthread_once(&once, once_creator);
DataBlock* pdb = new DataBlock(...);
pthread_setspecific(key, pdb);
// Теперь поток может пользоваться данными *pdb, как и локальными!
// цикл ожидания приходящих сигналов:
while (true) pause();
}
Все потоки используют один и тот же обработчик для всех сигналов; он выполняет одни и те же действия, но над различными объектами данных. Над каким объектом данных выполнить действие, обработчик «узнает» из контекста потока, в котором он выполняется:
static void handler(int signo, siginfo_t* info, void* context) {
DataBlock* pdb = (DataBlock*)pthread_getspecific(key);
// выполняем действия для своего потока ...
}
• Теперь, например из главного потока процесса (главный поток выбран для простоты - источником сигнала может быть произвольный поток, даже не этого процесса), требуемое действие вызывается возбуждением соответствующего сигнала:
sigqueue(getpid(), SIGRTMIN + K, val);
Это только скелетная схема, но на ее основе можно строить развитые протоколы обработки данных (пример взят из работоспособного приложения).
За пределы POSIX: сигналы в сети
А теперь, «на закуску», посмотрим справочную информацию по системной команде
kill
# use <имя-команды>
# use kill
kill - terminate or signal processes (POSIX)
kill [-signal_name|-signal_number] pid ...
kill -l
Options:
-signal_name Symbolic name of signal to send
-signal_number Integer representing a signal type
-l List symbolic signal names
<b> -n node Kill processes on the specified node.</b>
<b> (/bin/kill only)</b>
Where:
Valid signal names are:
SIGNULL SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP
SIGIOT SIGABRT SIGEMT SIGFPE SIGKILL SIGBUS
SIGSEGV SIGSYS SIGPIPE SIGALRM SIGTERM SIGUSR1
SIGUSR2 SIGCHLD SIGPWR SIGWINCH SIGURG SIGPOLL SIGSTOP SIGTSTP
SIGCONT SIGVTALARM SIGTTIN SIGTTOU
Note:
kill is also available as a shell builtin
Здесь нас ожидает сюрприз, который мы выделили в показанном фрагменте жирным шрифтом. И говорит эта строка о том, что в системе QNX сигнал может посылаться процессу, работающему на любом узле сети QNET. И это совершенно естественно, если вспомнить промелькнувшее выше замечание из технической документации, что сигнал в QNX - это пульс, то есть один из видов сообщений микроядра.
Таким образом, системная команда QNX
kill
kill
kill()
sigqueue()
kill
#include <sys/neutrino.h>
int SignalKill(uint32_t nd, pid_t pid,
int tid, int signo, int code, int value);
int SignalKill_r(uint32_t nd, pid_t pid, int tid, int signo,
int code int value);
где
nd
pid
tid
nd
ND_LOCAL_NODE
Дескриптор узла в сети QNET — понятие относительное; он может быть получен, например, вызовом
netmgr_strtond()
• Дескриптор, соответствующий, скажем, узлу «host», полученный на узле «А», может иметь значение N, но дескриптор того же узла, полученный на узле «В», будет иметь уже значение M, то есть дескриптор узла — это «дескриптор сетевого узла X, как он видится с сетевого узла Y».
• Тот же дескриптор узла «host» может быть определен как имеющий значение N, но уже через несколько секунд он может «сменить» свое значение на M, то есть значения, полученные
netmgr_strtond()
Эти и другие сложности относятся к особенностям программного использования QNET и требуют отдельного обстоятельного обсуждения. Однако они не являются предметом нашего текущего рассмотрения.
pid
pid
-pid
pid
tid
tid
tid