QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
cout << (islower(с) ? toupper(с) : c);
pclose(f);
return EXIT_SUCCESS;
}
Новый процесс выполняется с тем же окружением, что и родительский. Процесс, указанный в команде, запускается примерно следующим эквивалентом:
spawnlp(P_NOWAIT, shell_command, shell_command, "-с", command, (char*)NULL);
где
shell_command
/bin/sh
system()
popen()
Если
popen()
NULL
errno
EINVAL
mode
ENOSYS
popen()
pclose()
При использовании
system()
Клонирование процесса
Вызов
fork()
fork()
#include <process.h>
pid_t fork(void);
Действие вызова
fork()
• Порождается дочерний процесс, которому системой присваивается новое уникальное значение PID.
• Дочерний процесс получает собственные копии файловых дескрипторов, открытых в родительском процессе в точке выполнения
fork()
• Для дочернего процесса его значения
tms_utime
tms_stime
tms_cutime
tms_cstime
Сигнальные маски (подробнее об этом будет рассказано ниже) для дочернего процесса инициализируются пустыми сигнальными наборами (независимо от сигнальных масок, установленных родительским процессом).
Если вызов функции завершился неудачно, функция возвращает -1 и устанавливает
errno
EAGAIN
ENOMEM
ENOSYS
fork()
А вот с кодом возврата этой функции в случае удачи сложнее и гораздо интереснее. Дело в том, что для одного вызова
fork()
fork()
pid_t pid = fork();
if (pid == -1) perror("fork"), exit(EXIT_FAILURE);
if (pid == 0) {
// ... этот код выполняется в дочернем процессе ...
exit(EXIT_SUCCESS);
}
if (pid > 0) {
// ... этот код выполняется в родительском процессе ...
do { // ожидание завершения порожденного процесса
wpid = waitpid(pid, &status, 0);
} while(WIFEXITED(status) == 0);
exit(WEXITSTATUS(status));
}
Эта схема порождения процесса, его клонирование, настолько широко употребляется, особенно при построении самых разнообразных серверов, что для нее была создана специальная техника, построенная на вызове
fork()
Вот как выглядит простейший ретранслирующий TCP/IP-сервер, заимствованный из нашей более ранней публикации [4] (обработка ошибок полностью исключена, чтобы упростить пример):
int main(int argc, char* argv[]) {
// создание и подготовка прослушивающего сокета:
int rc, ls = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr); // специфика QNX
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT); // PORT - константа