Автор работы: Пользователь скрыл имя, 29 Марта 2013 в 16:51, контрольная работа
Процесс Р3 ожидает установленного им события от источника событий и одновременно готов принять уведомление от процесса Р2. Если приходит уведомление от Р2, то Р3 открывает файл для чтения, читает информацию из файла, выводит на терминал и завершает свою работу, передав статус завершения процессу Р1. Если раньше возникает установленное событие, то Р3 выводит на терминал сообщение об этом и завершает работу, передав статус завершения процессу Р1.
1.Обоснование выбранной структуры приложения
2.Обоснование выбранных механизмов синхронизации и взаимодействия процессов
3.Исходный текст приложения
Запускается процесс Р1, который создает источник событий, создает пустой файл и запускает процессы Р2 и Р3. Процесс Р1 с интервалом времени ∆t=1 сек увеличивает значение источника событий на 1. Процесс Р1 завершает свою работу, когда завершаются оба дочерних процесса Р2 и Р3.
Процесс Р2
ожидает установленного им события.
После наступления события
Процесс Р3 ожидает установленного им события от источника событий и одновременно готов принять уведомление от процесса Р2. Если приходит уведомление от Р2, то Р3 открывает файл для чтения, читает информацию из файла, выводит на терминал и завершает свою работу, передав статус завершения процессу Р1. Если раньше возникает установленное событие, то Р3 выводит на терминал сообщение об этом и завершает работу, передав статус завершения процессу Р1.
Приложение представляет собой
три исполняемых модуля m1, m2, m3, на
базе которых запускаются процессы
P1, P2 и P3 соответственно. Выбор полноценных
процессов вместо более простых в применении
нитей обусловлен возможностью в этом
случае реализовать процессы P1, P2 и P3 так,
что ошибка в одном из них не приведёт
к отказу всего приложения.
Это – следствие раздельного адресного
пространства процессов. При этом возникают
проблемы: меньше доступных механизмов
синхронизации, сложность организации
обмена данных между процессами и т.п.
Но все они решаются. Также стоит отметить
большее время переключения контекста
при использовании процессов по сравнению
с нитями. Однако для данной задачи не
задано требуемое время реакции процессов
на события, поэтому это не является существенным
недостатком.
Основной модуль – m1. Он создаёт источник событий, пустой файл и запускает процессы P2 и Р3. Отсчёт времени выполняется при помощи специального объекта ОС QNX "таймер", работающего в периодическом режиме с периодом 1 сек. Каждый раз по истечении интервала времени 1 сек таймер посылает процессу P1 сигнал с номером SIGRTMIN, обработчик которого увеличивает значение источника событий и посылает сигнал SIGRTMIN+1 всем процессам из группы процессов P1 при помощи функции killpg(). Таким образом, процесс P1 выступает в роли единого "источника времени" для процессов P2 и P3. Работа процесса P1 завершается при возникновении одного из двух событий: завершении процессов P2 и Р3 или по истечении допустимого времени ожидания 30 сек.
Процесс P2 обрабатывает сигнал с номером SIGRTMIN+1, увеличивая свой собственный счётчик времени. Исключение потери сигналов обеспечивается установкой флага SA_SIGINFO, дающего указание ОС ставить сигнал в очередь при его повторном приходе.
Каждый из процессов P2 и P3 получает значение своего события из текстового файла с настройками config, который должен находиться в одном каталоге с исполняемыми модулями. Формат файла: <время2> <время3>. Такая организация позволяет легко изменять поведение приложения.
Процесс P2 в начале своей работы получает ID процесса P3 от процесса-родителя Р1 и ждёт момент наступления своего события. При возникновении события выполняет действия, предусмотренные заданием, т.е. открывает файл на запись созданный процессом Р1, записывает в него текст “Text from P2” и посылает сигнал SIGRTMIN+2 процессу P3. После этого P2 завершается.
Процесс P3 реагирует на приход двух сигналов: SIGRTMIN+1 и SIGRTMIN+2. По сигналу SIGRTMIN+1 процесс Р3 завершает свою работу.
По сигналу SIGRTMIN+2 процесс P3 выполняет следующие действия: открывает файл на чтение созданный процессом Р1, читает содержащуюся в нем информацию и выводит ее на терминал, после чего завершает свою работу.
Графическая иллюстрация структуры приложения приведена на рисунке 1.
Синхронизация процессов осуществляется при помощи механизма сигналов и функции ожидания завершения процесса waitpid().
Механизм сигналов подходит для реализации передачи событий от процесса-источника к процессу-приёмнику. В отличие от других средств его легко применять для процессов.
Для обмена данными между процессами использовался общий файл, который создается процессом Р1. Процесс Р2 открывает этот файл на запись и записывает в него данные, а затем закрывает его. Процесс Р3 открывает этот файл на чтение и считывает из него данные, после чего закрывает его.
#define BUF_LEN 200
// размер общей памяти P2 и P3
#define TIMEOUT 30
// время таймаута при ожидании
// процессами какого-либо события
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <process.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "common.h"
int count=0; //счётчик времени
// обработчик сигнала SIGRTMIN
void sigrt0(int signo,siginfo_t *info,void *other){
count++;
//увеличиваем счётчик
printf("%d\n",count);
//вывод его значение на экран
killpg(getpid(),SIGRTMIN+1); //посылаем сигнал
SIGRTMIN+1
//нашей группе процессов
}
//точка входа в программу
int main(int argc,char **argv){
struct sigaction sigact;
struct sigevent evsource;
sigset_t
set;
timer_t
timerid;
struct itimerspec timerval;
int
res1;
int
res2;
pid_t
pid1;
pid_t
pid2;
int
status;
FILE
*f;
char
pid2str[20]
puts("\n\nP1: started");
sigact.sa_sigaction=sigrt0; //регистрируем обработчик
сигнала
//SIGRTMIN
sigemptyset(&sigact.sa_mask);
sigact.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN,&sigact,0);
evsource.sigev_notify=SIGEV_
//при срабатывании
evsource.sigev_signo=SIGRTMIN;
res1=timer_create(CLOCK_
if (res1!=0){
perror("P1: cannot create timer");
exit(-1);
}
//устанавливаем время срабатывания таймера
1 сек
timerval.it_value.tv_sec=1; timerval.it_value.tv_nsec=0;
timerval.it_interval.tv_sec=1; timerval.it_interval.tv_nsec=
f=fopen("temp","w");
//создаем файл с именем "temp"
if (f==0) return -1;
fclose(f);
pid2=spawnl(P_NOWAIT,"./m3",".
if (pid2==-1) {perror("P1: cannot spawn P3"); return
-1;}
itoa(pid2, pid2str, 10);
pid1=spawnl(P_NOWAIT,"./m2",".
//передаем ему ID процесса Р3
if (pid1==-1) {perror("P1: cannot spawn P2"); return
-1;}
usleep(500*1000);
//маскируем сигнал SIGRTMIN+1
sigemptyset(&set);
sigaddset(&set,SIGRTMIN+1);
sigprocmask(SIG_BLOCK,&set,0);
puts("P1: start source of events");
timer_settime(timerid,0,&
while (count<=TIMEOUT){ //ждём завершения
Р2 и Р3 или таймаута
if (res1!=pid1) res1=waitpid(pid1,&status,
if (res2!=pid2) res2=waitpid(pid2,&status,
if((res1==pid1)&(res2==pid2)) break;
}
if ((res1==pid1)&(res2==pid2)) puts("P1: ok");
else {
puts("P1: timeout");
kill(pid1,SIGKILL);
kill(pid2,SIGKILL);
}
timer_delete(timerid); // удаляем таймер
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <process.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "common.h"
int count=0;
// местный счётчик времени
int _time,event=0;
//функция получения из файла config события
для процесса P2
int getevent(){
FILE *f;
int i1,i2;
f=fopen("config","rt"); //открываем
if (f==0) return -1; //проверяем
if (fscanf(f,"%d %d",&i1,&i2)!=2) return -1;
//читаем
fclose(f); //закрываем
return i1; //возвращаем
}
// обработчик сигнала SIGRTMIN+1 (источник
события - p1)
void sigrt1(int signo,siginfo_t *info,void *other){
count++; //увеличиваем счётчик
if (count==_time) event=1; //если он равен нашему
времени
//произошло наше событие
}
// точка входа p2
int main(int argc,char *argv[]){
int
fd=0;
char
*buf=0;
struct sigaction sigact;
int
res;
pid_t
pid;
int
status;
FILE
*f;
char
buffer[]=”Text from P2”;
pid=atoi(argv[1]);
puts("P2: started");
_time=getevent(); // читаем наше время
из файла config
if (_time==-1) {perror("P2: cannot read config"); return
-1;}
printf("P2: event time=%d\n",_time);
//регистрируем обработчик SIGRTMIN+1
sigact.sa_sigaction=sigrt1;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN+1,&sigact,
while (count<=TIMEOUT){ // ждём нашего события
pause();
//pause() блокирует выполнение
//программы до прихода сигнала,
//возвращается после обработки его
//обработчиком, т.е. этот цикл будет
//выполняться с периодом 1 сек
if (event){
//если наступило наше событие, работаем
//по заданию
puts("P2: event from P1");
f=fopen("temp","r+");
//открываем файл созданный Р1
fputs(buffer,f);
//и пишем в него текст
fclose(f);
//затем закрываем
kill(pid,SIGRTMIN+2); //посылаем
сигнал SIGRTMIN+2
//процессу P3
break;
}
}
puts("P2: ok");
return 0;
}
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <process.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "common.h"
// функция получения из файла config
события для процесса p3
int getevent(){
FILE *f;
int i1,i2;
f=fopen("config","rt");
if (f==0) return -1;
if (fscanf(f,"%d %d",&i1,&i2)!=2) return -1;
fclose(f);
return i2;
}
//обработчик сигналов (заглушка) SIGRTMIN+1,+2
(источники
//события - p1,p2)
void sigrtx(int signo,siginfo_t *info,void *other){}
int main(int argc,char **argv){
struct sigaction sigact;
sigset_t
set;
siginfo_t
info;
int
_time;
int
work;
int
count=0;
char
buffer[20];
FILE
*f;
puts("P3: started");
//маскируем сигналы SIGRTMIN+1,+2 (просто чтобы
обработчик не //вызывался)
sigemptyset(&set);
sigaddset(&set,SIGRTMIN+1);
sigaddset(&set,SIGRTMIN+2);
sigprocmask(SIG_BLOCK,&set,0);
_time=getevent(); // читаем
наше время из файла config
if (_time==-1) {perror("P3: cannot read config"); return
-1;}
printf("P3: event time=%d\n",_time);
//устанавливаем пустой обработчик сигналов
SIGRTMIN+1,+2
sigact.sa_sigaction=sigrtx;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN+1,&sigact,
sigact.sa_sigaction=sigrtx;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN+2,&sigact,
for (work=1;work==1;){ //пока не отработаем
по одному из
//сигналов
sigwaitinfo(&set,&info); //
ждём очередного сигнала
switch (info.si_signo){
// смотрим какой его номер
case SIGRTMIN+1:
// SIGRTMIN+1 - значит, от P1
count++;
// увеличиваем счётчик событий
if (count==_time){
// если наше событие
puts("P3: event from
P1");
work=0;
} //end if
break;
case SIGRTMIN+2:{
// SIGRTMIN+2 - значит, от P2
puts("P3: event from P2");
f=fopen("temp","r");
fgets(buffer,sizeof(*f),f);
strncpy(buffer, "P3: ", 4);
puts(buffer);
fclose(f);
work=0;
} //end case
break;
} //end switch
} //end for
puts("P3: ok");
return 0;
}