» » » Олег Цилюрик - QNX/UNIX: Анатомия параллелизма


Авторские права

Олег Цилюрик - QNX/UNIX: Анатомия параллелизма

Здесь можно купить и скачать "Олег Цилюрик - QNX/UNIX: Анатомия параллелизма" в формате fb2, epub, txt, doc, pdf. Жанр: Программное обеспечение, издательство Символ-Плюс, год 2006. Так же Вы можете читать ознакомительный отрывок из книги на сайте LibFox.Ru (ЛибФокс) или прочесть описание и ознакомиться с отзывами.
Олег Цилюрик - QNX/UNIX: Анатомия параллелизма
Рейтинг:
Название:
QNX/UNIX: Анатомия параллелизма
Издательство:
неизвестно
Год:
2006
ISBN:
5-93286-088-Х
Вы автор?
Книга распространяется на условиях партнёрской программы.
Все авторские права соблюдены. Напишите нам, если Вы не согласны.

Как получить книгу?
Оплатили, но не знаете что делать дальше? Инструкция.

Описание книги "QNX/UNIX: Анатомия параллелизма"

Описание и краткое содержание "QNX/UNIX: Анатомия параллелизма" читать бесплатно онлайн.



Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.

В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.






• ENOTDIR — префиксные компоненты пути исполняемого файла не являются каталогами;

Даже из этого очень краткого обзора вызова spawn() становятся очевидными некоторые вещи:

• Эта форма универсальна (самодостаточна), она позволяет обеспечить весь спектр разнообразных форм порождения нового процесса

• Она же и самая громоздкая форма, тяжеловесная для практического кодирования, поэтому в реальных текстах в большинстве случаев вы вместо нее встретите ее конкретизации: spawnl(), spawnle(), spawnlp(), spawnlpe(), spawnp(), spawnv(), spawnve(), spawnvp(), spawnvpe(). Все эти формы достаточно полно описаны в [1]. Функционально они эквивалентны spawn(), поэтому мы не станем на них детально останавливаться.

• Хотя вызов spawn() и упоминается в описаниях как POSIX-совместимый, в QNX он существенно расширен и модифицирован и поэтому в лучшем случае может квалифицироваться как «выполненный по мотивам» POSIX.

В качестве примера приведем использованную в [4] (глава Д. Алексеева «Утилита on») форму вызова для запуска программы (с именем, заданным в строке command) на удаленном узле node (например, /net/xxx) сети QNET (как вы понимаете, это совершенно уникальная возможность QNX, говорить о которой в рамках POSIX-совместимости просто бессмысленно):

int main() {

 char* command = "...", *node = "...";

 // параметры запуска не используются

 char* const argv[] = { NULL };

 struct inheritance inh;

 inh.flags = 0;

 // флаг удаленного запуска

 inh.flags |= SPAWN_SETND;

 // дескриптор хоста

 inh.nd = netmgr_strtond(node, NULL);

 pid_t pid = spawnp(command, 0, NULL, &inh, argv, NULL);

 ...

}

Использованная здесь форма spawnp() наиболее близка к базовой spawn() и отличается лишь тем, что для поиска файла программы используется переменная системного окружения PATH.

Приведем характерный пример вызова группы exec*():

int execl(const char* path, const char* arg0, const char* arg1, ...

 const char* argn, NULL);

где path — путевое имя исполняемого файла; arg0, …, argn — символьные строки, доступные процессу как список аргументов. Список аргументов должен завершаться значением NULL. Аргумент arg0 должен быть именем файла, ассоциированного с запускаемым процессом.

Примечание

Устоявшаяся терминология «запускаемый процесс» относительно exec*() явно неудачна и лишь вводит в заблуждение. Здесь гораздо уместнее говорить о замещении выполнявшегося до этой точки кода новым, выполнение которого начинается с точки входа главного потока замещающего процесса.

Примечание

Если вызов exec*() выполняется из многопоточного родительского процесса, то все выполняющиеся потоки этого процесса предварительно завершаются. Никакие функции деструкторов для них не выполняются.

Если вызов exec*() успешен, управление никогда уже не возвращается в точку вызова. В случае неудачи возвращается -1 и errno устанавливается так же, как описано выше для spawn().

В качестве примера работы вызова spawn*() (использование exec() аналогично) рассмотрим приложение (файлы p1.cc, p1ch.cc), в котором:

• Родительский процесс (p1) порождает дочерний (p1ch) и ожидает от него поступления сигнала SIGUSR1 (сигналы детально обсуждаются позже, но здесь попутно «вскроем» одну из их особенностей).

• Дочерний процесс периодически посылает родителю сигнал SIGUSR1.

• Родительский процесс может переустановить (с помощью параметров командной строки запуска) для дочернего: период посылки сигнала (1-й параметр задан в нашем приложении константой) и приоритет, с которым будет выполняться дочерний процесс (2-й параметр, в качестве которого ретранслируется единственный параметр команды запуска родителя).

Примечание

В данный момент нас интересует только то приложение, в котором дочерний процесс порождается вызовом spawnl(). Используемые приложением механизмы и понятия — сигналы UNIX приоритеты, наследование и инверсия приоритетов — будут рассмотрены позже, поэтому при первом чтении их можно опустить. Нам не хотелось перегружать текст дополнительными «пустыми» примерами, лишь иллюстрирующими применение одной функции. Это приложение, созданное «на будущее», позволит нам отследить крайне актуальный для систем реального времени вопрос о наличии (или отсутствии) наследования приоритетов при посылке сигналов (допустимо как одно, так и другое решение, но оно должно быть однозначно единственным для ОС).

Итак, родительское приложение (файл 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);

 }

}

Примечание

Для многих сигналов действием на их получение, предопределенным по умолчанию, является завершение процесса. (Реже встречается действие по умолчанию — игнорировать полученный сигнал при отсутствии явно установленной для него функции обработчика.) Достаточно странно, что завершение процесса предусмотрено как реакция по умолчанию на получение «пользовательских» сигналов SIGUSR1 и SIGUSR2. Если показанное выше приложение в процессе отладки запустить вызовом из командной строки (из командного интерпретатора или, например, файлового менеджера mqc), то результатом (на первый взгляд не столь ожидаемым) станет завершение интерпретатора командной строки (родительского процесса) и, как следствие, самого тестируемого приложения.

Вот как выглядит начальный участок совместной работы двух процессов:

# p1 15

parent main loop: priority = 10

SIG = 16: old priority = 10, new priority = 15

SIG = 16: old priority = 10, new priority = 15

parent main loop: priority = 10

SIG = 16: old priority = 10, new priority = 15

parent main loop: priority = 10

SIG = 16: old priority = 10, new priority = 15

parent main loop priority = 10

SIG = 16: old priority = 10, new priority = 15

parent main loop: priority = 10

SIG = 16: old priority = 10, new priority = 15

parent main loop: priority = 10

Отчетливо видно, что при посылке сигналов реального времени наследование приоритета посылающего процесса не происходит (дочернее приложение, посылающее сигнал, выполняется с приоритетом 15, а обработчик полученного сигнала в родительском процессе выполняется с приоритетом по умолчанию, равным 10).


На Facebook В Твиттере В Instagram В Одноклассниках Мы Вконтакте
Подписывайтесь на наши страницы в социальных сетях.
Будьте в курсе последних книжных новинок, комментируйте, обсуждайте. Мы ждём Вас!

Похожие книги на "QNX/UNIX: Анатомия параллелизма"

Книги похожие на "QNX/UNIX: Анатомия параллелизма" читать онлайн или скачать бесплатно полные версии.


Понравилась книга? Оставьте Ваш комментарий, поделитесь впечатлениями или расскажите друзьям

Все книги автора Олег Цилюрик

Олег Цилюрик - все книги автора в одном месте на сайте онлайн библиотеки LibFox.

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Отзывы о "Олег Цилюрик - QNX/UNIX: Анатомия параллелизма"

Отзывы читателей о книге "QNX/UNIX: Анатомия параллелизма", комментарии и мнения людей о произведении.

А что Вы думаете о книге? Оставьте Ваш отзыв.