Использование механизмов управления параллельными процессами и нитями при разработке приложения реального времени на языке С в среде ОС Q

Автор работы: Пользователь скрыл имя, 29 Марта 2013 в 16:51, контрольная работа

Краткое описание

Процесс Р3 ожидает установленного им события от источника событий и одновременно готов принять уведомление от процесса Р2. Если приходит уведомление от Р2, то Р3 открывает файл для чтения, читает информацию из файла, выводит на терминал и завершает свою работу, передав статус завершения процессу Р1. Если раньше возникает установленное событие, то Р3 выводит на терминал сообщение об этом и завершает работу, передав статус завершения процессу Р1.

Содержание работы

1.Обоснование выбранной структуры приложения
2.Обоснование выбранных механизмов синхронизации и взаимодействия процессов
3.Исходный текст приложения

Содержимое работы - 1 файл

v9last.doc

— 74.50 Кб (Скачать файл)

Задание и исходные данные

Вариант 9

Запускается процесс Р1, который  создает источник событий, создает  пустой файл и запускает процессы Р2 и Р3. Процесс Р1 с интервалом времени ∆t=1 сек увеличивает значение источника событий на 1. Процесс Р1 завершает свою работу, когда завершаются оба дочерних процесса Р2 и Р3.

Процесс Р2 ожидает установленного им события. После наступления события процесс  Р2 открывает на запись файл, созданный  процессом Р1, заносит в него текстовую  информацию, посылает уведомление процессу Р3 и завершает свою работу, передав Р1 свой статус завершения.

Процесс Р3 ожидает установленного им события от источника событий  и одновременно готов принять  уведомление от процесса Р2. Если приходит уведомление от Р2, то Р3 открывает  файл для чтения, читает информацию из файла, выводит на терминал и завершает свою работу, передав статус завершения процессу Р1. Если раньше возникает установленное событие, то Р3 выводит на терминал сообщение об этом и завершает работу, передав статус завершения процессу Р1.

 

Содержание

 

  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.

 

  1. Обоснование выбранных  механизмов синхронизации и взаимодействия процессов

Синхронизация процессов осуществляется при помощи механизма сигналов и  функции ожидания завершения процесса waitpid().

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

Для обмена данными между процессами использовался общий файл, который  создается процессом Р1. Процесс  Р2 открывает этот файл на запись и записывает в него данные, а затем закрывает его. Процесс Р3 открывает этот файл на чтение и считывает из него данные, после чего закрывает его.

 

  1. Исходный текст приложения

Файл common.h

#define BUF_LEN 200          // размер общей памяти P2 и P3 
#define TIMEOUT 30           // время таймаута при ожидании 
                            // процессами какого-либо события

Файл m1.c

#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_SIGNAL; //создаём таймер, который 
                                      //при срабатывании 
  evsource.sigev_signo=SIGRTMIN;      //будет генерировать 
                                      //сигнал SIGRTMIN 
  res1=timer_create(CLOCK_REALTIME,&evsource,&timerid); 
  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=0; 
 
  f=fopen("temp","w");     //создаем файл с именем "temp" 
  if (f==0) return -1; 
  fclose(f); 
 
  pid2=spawnl(P_NOWAIT,"./m3","./m3",0);   //запускаем Р3 
  if (pid2==-1) {perror("P1: cannot spawn P3"); return -1;} 
  itoa(pid2, pid2str, 10); 
  pid1=spawnl(P_NOWAIT,"./m2","./m2",pid2str,0);//запускаем Р2 и 
                                   //передаем ему 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,&timerval,0);  //запускаем таймер 

  while (count<=TIMEOUT){ //ждём завершения Р2 и Р3 или таймаута 
    if (res1!=pid1) res1=waitpid(pid1,&status,WEXITED); 
    if (res2!=pid2) res2=waitpid(pid2,&status,WEXITED); 
    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; 
}

Файл m2.c

#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,0); 
 
  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; 
}

Файл m3.c

#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,0); 
 
  sigact.sa_sigaction=sigrtx; 
  sigemptyset(&sigact.sa_mask); 
  sigact.sa_flags=SA_SIGINFO; 
  sigaction(SIGRTMIN+2,&sigact,0); 
 
  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; 
}




Информация о работе Использование механизмов управления параллельными процессами и нитями при разработке приложения реального времени на языке С в среде ОС Q