Мобильное программирование приложений реального времени в стандарте POSIX

       

restrict pid, const char


#include <spawn.h>
int posix_spawn (pid_t * restrict pid, const char *restrict path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *restrict attrp, char *const argv [restrict], char *const envp [restrict]); int posix_spawnp (pid_t *restrict pid, const char *restrict file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *restrict attrp, char *const argv [restrict], char *const envp [restrict]);
Листинг 3.1. Описание функций одношагового порождения процессов.
Закрыть окно




#include <spawn.h>
int posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions);
int posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions);
int posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, int fildes);
int posix_spawn_file_actions_addopen ( posix_spawn_file_actions_t * restrict file_actions, int fildes, const char *restrict path, int oflag, mode_t mode);
int posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, int fildes, int newfildes);
Листинг 3.2. Описание функций формирования и ликвидации объектов типа posix_spawn_file_actions_t.
Закрыть окно




#include <spawn.h>
int posix_spawnattr_init ( posix_spawnattr_t *attr);
int posix_spawnattr_destroy ( posix_spawnattr_t *attr);
int posix_spawnattr_getflags ( const posix_spawnattr_t *restrict attr, short *restrict flags);
int posix_spawnattr_setflags ( posix_spawnattr_t *attr, short flags);
int posix_spawnattr_getpgroup ( const posix_spawnattr_t *restrict attr, pid_t *restrict pgroup);
int posix_spawnattr_setpgroup ( posix_spawnattr_t *attr, pid_t pgroup);
Листинг 3.3. Описание функций формирования и опроса атрибутных объектов порождаемых процессов.
Закрыть окно




#include <spawn.h> #include <sched.h>
int posix_spawnattr_getschedparam ( const posix_spawnattr_t *restrict attr, struct sched_param *restrict schedparam);
int posix_spawnattr_setschedparam ( posix_spawnattr_t * restrict attr, const struct sched_param *restrict schedparam);
int posix_spawnattr_getschedpolicy ( const posix_spawnattr_t *restrict attr, int *restrict schedpolicy);
int posix_spawnattr_setschedpolicy ( posix_spawnattr_t *attr, int schedpolicy);
Листинг 3.4. Описание функций опроса и установки параметров и политики планирования в атрибутных объектах порождаемых процессов.
Закрыть окно




#include <spawn.h> #include <signal.h> int posix_spawnattr_getsigdefault ( const posix_spawnattr_t *restrict attr, sigset_t *restrict sigdefault);
int posix_spawnattr_setsigdefault ( posix_spawnattr_t * restrict attr, const sigset_t *restrict sigdefault);
int posix_spawnattr_getsigmask ( const posix_spawnattr_t *restrict attr, sigset_t *restrict sigmask);
int posix_spawnattr_setsigmask ( posix_spawnattr_t *restrict attr, const sigset_t *restrict sigmask);
Листинг 3.5. Описание функций опроса и установки подразумеваемой обработки и маски сигналов в атрибутных объектах порождаемых процессов.
Закрыть окно




typedef struct { short posix_attr_flags; pid_t posix_attr_pgroup; sigset_t posix_attr_sigmask; sigset_t posix_attr_sigdefault; int posix_attr_schedpolicy; struct sched_param posix_attr_schedparam; } posix_spawnattr_t;
typedef char *posix_spawn_file_actions_t;
int posix_spawn (pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv [], char *const envp []);
Листинг 3.6. Фрагмент возможного содержимого файла spawn.h.
Закрыть окно




int posix_spawn (pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv [], char *const envp []) {
/* Создадим новый процесс */ if ((*pid = fork()) == (pid_t) 0) { /* Порожденный процесс */ /* Позаботимся о группе процессов */ if (attrp->posix_attr_flags & POSIX_SPAWN_SETPGROUP) { /* Изменим унаследованную группу */ if (setpgid (0, attrp->posix_attr_pgroup) != 0) { /* Неудача */ exit (127); } }
/* Позаботимся о действующих идентификаторах */ /* пользователя и группы */ if (attrp->posix_attr_flags & POSIX_SPAWN_RESETIDS) { /* В данном случае неудачи быть не может */ setuid (getuid ()); setgid (getgid ()); }
/* Позаботимся о подразумеваемом способе */ /* обработки сигналов */ if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF) { struct sigaction deflt; sigset_t all_signals; int s;
deflt.sa_handler = SIG_DFL; deflt.sa_flags = 0;
sigfillset (&all_signals);
/* Цикл по всем сигналам */ for (s = 0; sigismember (&all_signals, s); s++) { if (sigismember (&attrp->posix_attr_sigdefault, s)) { if (sigaction (s, &deflt, NULL) == -1) { exit (127); } } } }
/* Проконтролируем остальные атрибуты */ /* . . . */
/* Подменим образ процесса */ execve (path, argv, envp); exit (127); } else { /* Родительский (вызывающий) процесс */ if (*pid == (pid_t) (-1)) return errno; return 0; } }
Листинг 3.7. Фрагмент возможной библиотечной реализации функции posix_spawn().
Закрыть окно




/* Запуск процесса с произвольным идентификатором */ /* пользователя */
uid_t old_uid; uid_t new_uid = ...;
old_uid = getuid (); setuid (new_uid);
posix_spawn (...);
setuid (old_uid);
Листинг 3.8. Пример установки характеристики порожденного процесса, не принадлежащей к числу контролируемых стандартными средствами.
Закрыть окно




posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_init ( &file_actions); posix_spawn_file_actions_addopen ( & file_actions, 1, "outfile", ...); posix_spawn_file_actions_adddup2 ( &file_actions, socket_pair [1], 0); posix_spawn_file_actions_addclose ( &file_actions, socket_pair [0]); posix_spawn_file_actions_addclose ( &file_actions, socket_pair [1]);
posix_spawn (..., &file_actions, ...); posix_spawn_file_actions_destroy ( &file_actions);
Листинг 3.9. Пример перенаправления стандартных ввода и вывода порождаемого процесса.
Закрыть окно




#include <spawn.h> #include <stdio.h> #include <sys/wait.h> #include <errno.h>
#define N 10000
int main (void) { char *s_argv [] = {"dummy", NULL}; char *s_env [] = {NULL};
int i;
for (i = 0; i &lt; N; i++) { if ((errno = posix_spawn ( NULL, "./dummy", NULL, NULL, s_argv, s_env)) != 0) { perror ("POSIX_SPAWN"); return (errno); } (void) wait (NULL); }
return 0; }
Листинг 3.10. Пример программы, порождающей в цикле практически пустые процессы с помощью функции posix_spawn().
Закрыть окно




real 34.37 user 12.01 sys 22.07
Листинг 3.11. Возможные результаты измерения времени работы программы, порождающей в цикле практически пустые процессы с помощью функции posix_spawn().
Закрыть окно




#include <signal.h> int sigqueue ( pid_t pid, int signo, const union sigval value);
Листинг 3.12. Описание функции sigqueue().
Закрыть окно




#include <signal.h>
int sigwaitinfo ( const sigset_t *restrict set, siginfo_t *restrict info);
int sigtimedwait ( const sigset_t *restrict set, siginfo_t * restrict info, const struct timespec *restrict timeout);
Листинг 3.13. Описание функций sigwaitinfo() и sigtimedwait().
Закрыть окно




#include <signal.h> int sigaltstack (const stack_t * restrict ss, stack_t *restrict oss);
Листинг 3.14. Описание функции sigaltstack().
Закрыть окно




#include <stdlib.h> #include <stdio.h> #include <signal.h> . . . stack_t sighstk; . . .
if ((sighstk.ss_sp = malloc( SIGSTKSZ)) == NULL) { perror ("malloc (SIGSTKSZ)"); /* Аварийное завершение */ } sighstk.ss_size = SIGSTKSZ; sighstk.ss_flags = 0; if (sigaltstack (&sighstk, (stack_t *) NULL) != 0) { perror ("SIGALTSTACK"); . . . } . . .
Листинг 3.15. Типичная схема определения альтернативного стека.
Закрыть окно




#include <setjmp.h>
int sigsetjmp ( sigjmp_buf env, int savemask);
void siglongjmp (sigjmp_buf env, int val);
Листинг 3.16. Описание функций sigsetjmp() и siglongjmp().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * * */ /* Многопотоковый вариант обеда философов */ /* с использованием сигналов реального времени */ /* * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <pthread.h> #include <time.h> #include <errno.h>
/* Число обедающих философов */ #define QPH 5
/* Время (в секундах) на обед */ #define FO 15
/* Длительность еды */ #define ernd (rand () % 3 + 1)
/* Длительность разговора */ #define trnd (rand () % 5 + 1)
/* Номер сигнала, используемого для захвата и освобождения вилок */ #define SIG_FORK SIGRTMIN
/* Номер сигнала, используемого для информирования философа */ #define SIG_PHIL SIGINT
static pthread_t pt_id [QPH]; /* Массив идентификаторов */ /* потоков - философов */ static int fork_busy [QPH] = {0, }; /* Состояние вилок */ static int phil_req [QPH] = {0, }; /* Невыполненные */ /* заявки на вилки */ static sigjmp_buf phil_env [QPH]; /* Массив буферов для */ /* нелокальных переходов */
static pid_t pid_wt; /* Идентификатор процесса,*/ /* контролирующего вилки */
static pthread_key_t phil_key; /* Ключ индивидуальных */ /* данных потоков-философов */
/* * * * * * * * * * * * * * * * * * * */ /* Функция обработки сигнала SIG_PHIL */ /* * * * * * * * * * * * * * * * * * * */ static void phil_eat (int signo) { int no; /* Номер философа, которому достался сигнал */
no = (int) pthread_getspecific (phil_key); if ((no > 0) && (no &lt;= QPH)) { siglongjmp (phil_env [no – 1], signo); } }
/* * * * * * * * * * * * * * * * * * * * * * */ /* Попытка выполнить заявку на захват вилок */ /* от философа номер no, если она есть */ /* * * * * * * * * * * * * * * * * * * * * * */ static void fork_lock (int no) { if (phil_req [no – 1] != 0) { /* Заявка есть. */ /* Вилки свободны? */ if ((fork_busy [no – 1] == 0) && (fork_busy [no % QPH] == 0)) { /* Выполним заявку */ fork_busy [no – 1] = fork_busy [no % QPH] = 1; phil_req [no – 1] = 0; (void) pthread_kill (pt_id [no – 1], SIG_PHIL); } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Стартовая функция потока, обслуживающего заявки на */ /* захват и освобождение вилок. */ /* Заявка передается в виде значения, ассоциированного */ /* с сигналом signo. */ /* Значение no > 0 запрашивает захват вилок для философа */ /* с номером no, no < 0 – освобождение вилок философа -no */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ void *start_waiter (void *signo) { siginfo_t sinfo; /* Структура для получения данных */ /* о сигнале */ int no; /* Номер философа, приславшего заявку */ sigset_t s_sgno; /* Маска ожидаемых сигналов */
pid_wt = getpid ();
/* Сформируем маску ожидаемых сигналов */ if ((sigemptyset (&s_sgno) != 0) || (sigaddset (&s_sgno, (int) signo) != 0)) { perror ("SIGEMPTYSET/SIGADDSET"); return (NULL); }
while (1) { if (sigwaitinfo (&s_sgno, &sinfo) != (int) signo) { return (NULL); } else { /* Поступила заявка. */ /* Посмотрим, что от нас хотят */ if ((no = sinfo.si_value.sival_int) > 0) { /* Заявка на захват вилок. */ /* Запомним ее ... */ phil_req [no – 1] = 1; /* ... и попробуем выполнить */ fork_lock (no); } else { /* Освобождение вилок */ no = -no; fork_busy [no – 1] = fork_busy [no % QPH] = 0; /* Попробуем выполнить заявки от соседей */ fork_lock (no % QPH + 1); fork_lock (no == 1 ? QPH : (no – 1)); } } /* Другие сигналы нас не интересуют */ } /* while (1) */ }
/* * * * * * * * * * * * * * * * * * */ /* Стартовая функция потока-философа. */ /* Аргумент – номер философа */ /* * * * * * * * * * * * * * * * * * */ void *start_phil (void *no) { int fo; /* Время до конца обеда */ int t; /* Время очередного отрезка еды или беседы */ time_t tbe; /* Время, когда философу понадобились вилки */ union sigval sval; /* Значение посылаемого сигнала: */ /* (int) no – заказ вилок */ /* -(int) no – освобождение вилок */
/* Запомним значение аргумента в качестве */ /* индивидуальных данных потока */ (void) pthread_setspecific (phil_key, no);
/* Подготовка к обеду */ fo = FO;
if (sigsetjmp (phil_env [(int) no – 1], 1) != 0) { /* Сюда придем после нелокального перехода */ /* из обработчика сигнала SIG_PHIL. */ /* Философ просил вилки и получил их */ printf ("Философ %d ест\n", (int) no); t = ernd; sleep (t); /* Нужно вычесть времена еды и ожидания вилок */ fo -= (int) (time ((time_t *) NULL) – tbe) + t; /* Отдает вилки */ sval.sival_int = -((int) no); (void) sigqueue (pid_wt, SIG_FORK, sval); }
while (fo > 0) { printf ("Философ %d беседует\n", (int) no); t = trnd; sleep (t); fo -= t;
/* Пытается взять вилки */ tbe = time ((time_t *) NULL); sval.sival_int = (int) no; (void) sigqueue (pid_wt, SIG_FORK, sval);
/* Пока вилки заняты, приходится беседовать... */ printf ("Философ %d беседует в ожидании вилок\n", (int) no); sleep (fo); fo = 0; } /* while */ printf ("Философ %d закончил обед\n", (int) no);
return (NULL); }
/* * * * * * * * * * */ /* Организация обеда */ /* * * * * * * * * * */ int main (void) { int no; /* Номер философа */ struct sigaction sact; /* Структура для обработки */ /* обычных сигналов */ pthread_t pt_wt; /* Идентификатор потока, */ /* управляющего вилками */
/* Блокируем сигнал SIG_FORK */ if ((sigemptyset (&sact.sa_mask) == 0) && (sigaddset (&sact.sa_mask, SIG_FORK) == 0)) { (void) pthread_sigmask (SIG_BLOCK, &sact.sa_mask, (sigset_t *) NULL); }
/* Установим для сигнала SIG_FORK флаг SA_SIGINFO */ sact.sa_flags = SA_SIGINFO; sact.sa_sigaction = (void (*) (int, siginfo_t *, void *)) SIG_DFL; (void) sigaction (SIG_FORK, &sact, (struct sigaction *) NULL);
/* Установим реакцию на сигнал SIG_PHIL */ sact.sa_handler = phil_eat; sigemptyset (&sact.sa_mask); sact.sa_flags = 0; (void) sigaction (SIG_PHIL, &sact, (struct sigaction *) NULL);
/* Создадим поток, захватывающий и освобождающий вилки */ if ((errno = pthread_create (&pt_wt, NULL, start_waiter, (void *) SIG_FORK)) != 0) { perror ("PTHREAD_CREATE-1"); return (errno); }
/* Создадим ключ индивидуальных данных */ if ((errno = pthread_key_create (&phil_key, (void (*) (void *)) NULL)) != 0) { perror ("PTHREAD_KEY_CREATE"); return (errno); }
/* Все – к столу */ for (no = 1; no &lt;= QPH; no++) { if ((errno = pthread_create (&pt_id [no – 1], NULL, start_phil, (void *) no)) != 0) { perror ("PTHREAD_CREATE"); return (no); } }
/* Ожидание завершения обеда */ for (no = 1; no &lt;= QPH; no++) { (void) pthread_join (pt_id [no – 1], NULL); }
(void) pthread_key_delete (phil_key);
/* Завершим поток, контролирующий вилки */ (void) pthread_cancel (pt_wt); (void) pthread_join (pt_wt, NULL);
return 0; }
Листинг 3.17. Пример реализации обеда философов с использованием сигналов реального времени.
Закрыть окно




Философ 1 беседует Философ 2 беседует Философ 3 беседует Философ 4 беседует Философ 5 беседует Философ 4 беседует в ожидании вилок Философ 4 ест Философ 2 беседует в ожидании вилок Философ 2 ест Философ 3 беседует в ожидании вилок Философ 4 беседует Философ 1 беседует в ожидании вилок Философ 5 беседует в ожидании вилок Философ 5 ест Философ 2 беседует Философ 3 ест Философ 5 беседует Философ 1 ест Философ 2 беседует в ожидании вилок Философ 4 беседует в ожидании вилок Философ 3 беседует Философ 4 ест Философ 5 беседует в ожидании вилок Философ 1 беседует Философ 2 ест Философ 2 беседует Философ 4 закончил обед Философ 1 беседует в ожидании вилок Философ 5 ест Философ 2 беседует в ожидании вилок Философ 2 ест Философ 3 беседует в ожидании вилок Философ 3 закончил обед Философ 1 закончил обед Философ 5 закончил обед Философ 2 закончил обед
Листинг 3.18. Возможные результаты выполнения программы, реализующей обед философов с использованием сигналов реального времени.
Закрыть окно




#include <time.h> int clock_nanosleep ( clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp);
Листинг 3.19. Описание функции clock_nanosleep().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * */ /* Организация периодических процессов */ /* с помощью функции clock_nanosleep() */ /* * * * * * * * * * * * * * * * * * * */
#define _XOPEN_SOURCE 600
#include <time.h> #include <stdio.h> #include <unistd.h>
/* * * * * * * * * * * * * * * * * * * * */ /* Сложение двух структур типа timespec */ /* * * * * * * * * * * * * * * * * * * * */ static void tmspc_add (struct timespec *a1, struct timespec *a2, struct timespec *res) { res->tv_sec = a1->tv_sec + a2->tv_sec + (a1->tv_nsec + a2->tv_nsec) / 1000000000; res->tv_nsec = (a1->tv_nsec + a2->tv_nsec) % 1000000000; }
/* * * * * * * * * * * * * * * * * * * */ /* Организация периодического процесса */ /* * * * * * * * * * * * * * * * * * * */ int main (void) { struct timespec t_bp; /* Время начала очередного */ / *периода выполнения */ struct timespec prd = {1, 250000000}; /* Период */ /* выполнения: 1.25 сек */ clockid_t clk_id = CLOCK_REALTIME; /* Идентификатор */ /* используемых часов */ struct timespec t_tmp; int i; /* Запомним время начала выполнения */ (void) clock_gettime (clk_id, &t_bp); printf ("Начало выполнения: %ld сек %ld нсек\n", t_bp.tv_sec, t_bp.tv_nsec);
for (i = 0; i &lt; 8; i++) { /* Содержательные действия. */ /* Предполагается, что они укладываются в период */ sleep (1);
/* Доспим до конца периода */ tmspc_add (&t_bp, &prd, &t_bp); (void) clock_nanosleep (clk_id, TIMER_ABSTIME, &t_bp, NULL);
(void) clock_gettime (clk_id, &t_tmp); printf ("Конец периода: %ld сек %ld нсек\n", t_tmp.tv_sec, t_tmp.tv_nsec); }
return 0; }
Листинг 3.20. Пример применения функции clock_nanosleep() для организации периодического процесса.
Закрыть окно




Начало выполнения: 1079080828 сек 194254000 нсек Конец периода: 1079080829 сек 460021000 нсек Конец периода: 1079080830 сек 710023000 нсек Конец периода: 1079080831 сек 960020000 нсек Конец периода: 1079080833 сек 210021000 нсек Конец периода: 1079080834 сек 460023000 нсек Конец периода: 1079080835 сек 710021000 нсек Конец периода: 1079080836 сек 960094000 нсек Конец периода: 1079080838 сек 210022000 нсек
Листинг 3.21. Возможные результаты выполнения программы, использующей функцию clock_nanosleep() для организации периодического процесса.
Закрыть окно




#include <signal.h> #include <time.h> int timer_create ( clockid_t clockid, struct sigevent *restrict evp, timer_t *restrict timerid);
Листинг 3.22. Описание функции timer_create().
Закрыть окно




#include <time.h> int timer_delete (timer_t timerid);
Листинг 3.23. Описание функции timer_delete().
Закрыть окно




#include <time.h>
int timer_gettime (timer_t timerid, struct itimerspec *value);
int timer_settime ( timer_t timerid, int flags, const struct itimerspec *restrict value, struct itimerspec *restrict ovalue);
int timer_getoverrun (timer_t timerid);
Листинг 3.24. Описание функций timer_gettime(), timer_settime() и timer_getoverrun().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * * */ /* Многопотоковый вариант обеда философов */ /* с использованием сигналов реального времени */ /* и таймера для контроля длительности обеда */ /* * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <pthread.h> #include <time.h> #include <errno.h>
/* Число обедающих философов */ #define QPH 5
/* Время (в секундах) на обед */ #define FO 15
/* Длительность еды */ #define ernd (rand () % 3 + 1)
/* Длительность разговора */ #define trnd (rand () % 5 + 1)
/* Номер сигнала, используемого для захвата */ /* и освобождения вилок */ #define SIG_FORK SIGRTMIN
/* Номер сигнала, используемого таймером */ /* для окончания обеда */ #define SIG_DEND (SIGRTMIN + 1) /* Номер сигнала, используемого */ /* для информирования философа */ #define SIG_PHIL SIGINT
static pthread_t pt_id [QPH]; /* Массив идентификаторов */ /* потоков-философов */ static int fork_busy [QPH] = {0, }; /* Состояние вилок */ static int phil_req [QPH] = {0, }; /* Невыполненные */ /* заявки на вилки */ static sigjmp_buf phil_env [QPH]; /* Массив буферов для */ /* нелокальных переходов */
static pid_t pid_wt; /* Идентификатор процесса, */ /* контролирующего вилки */
static pthread_key_t phil_key; /* Ключ индивидуальных */ /* данных потоков-философов */
/* * * * * * * * * * * * * * * * * * */ /* Функция обработки сигнала SIG_PHIL */ /* * * * * * * * * * * * * * * * * * */ static void phil_eat (int signo) { int no; /* Номер философа, которому достался сигнал */
no = (int) pthread_getspecific (phil_key); if ((no > 0) && (no &lt;= QPH)) { siglongjmp (phil_env [no – 1], signo); } }
/* * * * * * * * * * * * * * * * * * */ /* Деструктор индивидуальных данных */ /* потоков-философов */ /* * * * * * * * * * * * * * * * * * */ static void phil_destructor (void *no) { printf ("Философ %d закончил обед\n", (int) no); }
/* * * * * * * * * * * * * * * * * * * * * * * */ /* Функция, вызываемая при срабатывании таймера, */ /* контролирующего длительность обеда */ /* * * * * * * * * * * * * * * * * * * * * * ** */ static void end_ph_dinner (union sigval dummy) { int i;
for (i = 0; i &lt; QPH; i++) { (void) pthread_cancel (pt_id [i]); } }
/* * * * * * * * * * * * * * * * * * * * * */ /* Попытка выполнить заявку на захват вилок */ /* от философа номер no, если она есть */ /* * * * * * * * * * * * * * * * * * * * * */ static void fork_lock (int no) { if (phil_req [no – 1] != 0) { /* Заявка есть. */ /* Вилки свободны? */ if ((fork_busy [no – 1] == 0) && (fork_busy [no % QPH] == 0)) { /* Выполним заявку */ fork_busy [no – 1] = fork_busy [no % QPH] = 1; phil_req [no – 1] = 0; (void) pthread_kill (pt_id [no – 1], SIG_PHIL); } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Стартовая функция потока, обслуживающего заявки на */ /* захват и освобождение вилок. */ /* Заявка передается в виде значения, ассоциированного */ /* с сигналом signo. */ /* Значение no > 0 запрашивает захват вилок для философа */ /* с номером no, no < 0 – освобождение вилок философа -no */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ void *start_waiter (void *signo) { siginfo_t sinfo; /* Структура для получения данных */ /* о сигнале */ int no; /* Номер философа, приславшего */ /* заявку */ sigset_t s_sgno; /* Маска ожидаемых сигналов */
pid_wt = getpid (); /* Сформируем маску ожидаемых сигналов */ if ((sigemptyset (&s_sgno) != 0) || (sigaddset (&s_sgno, (int) signo) != 0)) { perror ("SIGEMPTYSET/SIGADDSET"); return (NULL); }
while (1) { if (sigwaitinfo (&s_sgno, &sinfo) != (int) signo) { return (NULL); } else { /* Поступила заявка. */ /* Посмотрим, что от нас хотят */ if ((no = sinfo.si_value.sival_int) > 0) { /* Заявка на захват вилок. */ /* Запомним ее ... */ phil_req [no – 1] = 1; /* ... и попробуем выполнить */ fork_lock (no); } else { /* Освобождение вилок */ no = -no; fork_busy [no – 1] = fork_busy [no % QPH] = 0; /* Попробуем выполнить заявки от соседей */ fork_lock (no % QPH + 1); fork_lock (no == 1 ? QPH : (no – 1)); } } /* Другие сигналы нас не интересуют */ } /* while (1) */ }
/* * * * * * * * * * * * * * * * * * */ /* Стартовая функция потока-философа. */ /* Аргумент – номер философа */ /* * * * * * * * * * * * * * * * * * */ void *start_phil (void *no) { union sigval sval; /* Значение посылаемого сигнала: */ /* (int) no – заказ вилок */ /* -(int) no – освобождение вилок */
/* Запомним значение аргумента в качестве */ /* индивидуальных данных потока */ (void) pthread_setspecific (phil_key, no); if (sigsetjmp (phil_env [(int) no – 1], 1) != 0) { /* Сюда придем после нелокального перехода */ /* из обработчика сигнала SIG_PHIL. */ /* Философ просил вилки и получил их */ printf ("Философ %d ест\n", (int) no); if (sleep (ernd) != 0) { return (NULL); } /* Отдает вилки */ sval.sival_int = -((int) no); (void) sigqueue (pid_wt, SIG_FORK, sval); }
{ /* Обед */ printf ("Философ %d беседует\n", (int) no); if (sleep (trnd) != 0) { return (NULL); }
/* Пытается взять вилки */ sval.sival_int = (int) no; (void) sigqueue (pid_wt, SIG_FORK, sval);
/* Пока вилки заняты, приходится беседовать... */ printf ("Философ %d беседует в ожидании вилок\n", (int) no); sleep (FO); } /* Конец обеда */
return (NULL); }
/* * * * * * * * * * */ /* Организация обеда */ /* * * * * * * * * * */ int main (void) { int no; /* Номер философа */ struct sigaction sact; /* Структура для обработки */ /* обычных сигналов */ struct sigevent dend; /* Структура для генерации */ /* сигнала таймером */ timer_t dend_tmrid; /* Идентификатор таймера, */ /* контролирующего длительность */ /* обеда */ struct itimerspec dend_tmrsp = {{0, 0}, {FO, 0}}; /* Структура для взведения таймера, */ /* контролирующего длительность обеда */ pthread_t pt_wt; /* Идентификатор потока, управляющего */ /* вилками */
/* Блокируем сигнал SIG_FORK */ if ((sigemptyset (&sact.sa_mask) == 0) && (sigaddset (&sact.sa_mask, SIG_FORK) == 0)) { (void) pthread_sigmask (SIG_BLOCK, &sact.sa_mask, (sigset_t *) NULL); }
/* Установим для сигнала SIG_FORK флаг SA_SIGINFO */ sact.sa_flags = SA_SIGINFO; sact.sa_sigaction = (void (*) (int, siginfo_t *, void *)) SIG_DFL; (void) sigaction (SIG_FORK, &sact, (struct sigaction *) NULL);
/* Установим реакцию на сигнал SIG_PHIL */ sact.sa_handler = phil_eat; sigemptyset (&sact.sa_mask); sact.sa_flags = 0; (void) sigaction (SIG_PHIL, &sact, (struct sigaction *) NULL);
/* Создадим поток, захватывающий и освобождающий вилки */ if ((errno = pthread_create (&pt_wt, NULL, start_waiter, (void *) SIG_FORK)) != 0) { perror ("PTHREAD_CREATE-1"); return (errno); }
/* Создадим ключ индивидуальных данных */ if ((errno = pthread_key_create (&phil_key, phil_destructor)) != 0) { perror ("PTHREAD_KEY_CREATE"); return (errno); } /* Создадим и взведем таймер, */ /* контролирующий длительность обеда */ dend.sigev_notify = SIGEV_THREAD; dend.sigev_signo = SIG_DEND; dend.sigev_notify_function = end_ph_dinner; dend.sigev_notify_attributes = NULL; if (timer_create (CLOCK_REALTIME, &dend, &dend_tmrid) != 0) { perror ("TIMER_CREATE"); return (-1); } if (timer_settime (dend_tmrid, 0, &dend_tmrsp, NULL) != 0) { perror ("TIMER_SETTIME"); return (-1); }
/* Все – к столу */ for (no = 1; no &lt;= QPH; no++) { if ((errno = pthread_create (&pt_id [no – 1], NULL, start_phil, (void *) no)) != 0) { perror ("PTHREAD_CREATE"); return (no); } }
/* Ожидание завершения обеда */ for (no = 1; no &lt;= QPH; no++) { (void) pthread_join (pt_id [no – 1], NULL); }
(void) pthread_key_delete (phil_key); (void) timer_delete (dend_tmrid);
/* Поток, контролирующий вилки, */ /* можно не терминировать и не ждать */
return 0; }
Листинг 3.25. Пример реализации обеда философов с использованием сигналов реального времени и таймера.
Закрыть окно




Философ 1 беседует Философ 2 беседует Философ 3 беседует Философ 4 беседует Философ 5 беседует Философ 4 беседует в ожидании вилок Философ 4 ест Философ 2 беседует в ожидании вилок Философ 2 ест Философ 3 беседует в ожидании вилок Философ 4 беседует Философ 1 беседует в ожидании вилок Философ 5 беседует в ожидании вилок Философ 5 ест Философ 2 беседует Философ 3 ест Философ 5 беседует Философ 1 ест Философ 2 беседует в ожидании вилок Философ 4 беседует в ожидании вилок Философ 3 беседует Философ 4 ест Философ 5 беседует в ожидании вилок Философ 1 беседует Философ 2 ест Философ 2 беседует Философ 1 беседует в ожидании вилок Философ 4 беседует Философ 1 ест Философ 2 беседует в ожидании вилок Философ 3 беседует в ожидании вилок Философ 3 ест Философ 1 беседует Философ 5 ест Философ 4 беседует в ожидании вилок Философ 5 беседует Философ 1 закончил обед Философ 2 закончил обед Философ 3 беседует Философ 4 закончил обед Философ 5 закончил обед Философ 3 беседует в ожидании вилок Философ 3 закончил обед
Листинг 3.26. Возможные результаты выполнения программы, реализующей обед философов с использованием сигналов реального времени и таймера.
Закрыть окно



Содержание раздела