ТВПиС лабораторная работа 2 / lab02
.doc
Белорусский государственный университет
информатики и радиоэлектроники
Факультет заочного, вечернего и дистанционного обучения
Специальность “Программное обеспечение информационных технологий”
Лабораторная работа №2
по дисциплине «Теория вычислительных процессов и структур»
Бондаренко Александра Леонидовича
Группа 701021с
Зачетная книжка 701021с-06
Электронный адрес AlexBond2@tut.by
Минск – 2009
СРЕДСТВА МЕЖПРОЦЕССНОГО ВЗАИМОДЕЙСТВИЯ ОС
Цель работы – изучить методы и средства взаимодействия процессов в ОС Linux.
Задание.
Cоздать два дочерних процесса. Родительский процесс создаёт семафор (сем1) и общий файл отображенный в память. Оба дочерних процесса непрерывно записывают в файл по 100 строк вида: номер_строки pid_процесса текущее_время (мсек). Всего процессы должны записать 1000 строк. Семафор сем1 используется процессами для разрешения кому из процессов получить доступ к файлу. Родительский процесс читает из файла по 75 строк и выводит их на экран. Дочерние процессы начинают операции с файлом после получения сигнала SIGUSR1 от родительского процесса.
Решение.
Описание алгоритма: создается/очищается общий файл temp и отображается в память функцией mmap(). Создаются семафоры. Будем использовать 4 семафора, два для потока, один для блокирования записи/чтения и один для передачи номера строки. После создания семафоров, выставляем значение с помощью функции semctl(), тем самым организуем корректную работу. Далее создается два дочерних процесса, каждый дочерний процесс привязывается сигналом к функции c_action() которая разрешает начало выполнение операции. После создания процессов родительский процесс посылает сигнал SIGUSR1 каждому дочернему процессу.
Дочерний процессы, получив сигнал и разрешение на запись, записывает свои 100 строк и переключает семафоры, ожидая пока выполнит свою запись другой процесс.
Родительский процесс проверяет, есть ли строки для чтения через 4-й семафор и после чего считывает 75 строк и выводит на экран, блокируя доступ к файлу через 3-й семафор.
Листинг программы
#include <linux/sem.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
int start = 0;
#define LEN 20
pid_t chpid [2];
int main (int argc, char *argv [])
{
struct timeval c_time;
void c_action (int);
static struct sigaction pact, cact;
char str [LEN];
id_t pid;
// создаем общий файл
unlink("temp");
int fd = open("temp",O_CREAT|O_RDWR);
char* map = mmap(0,1000*LEN,PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
if(map == MAP_FAILED){
perror("mmap");
return 1;}
// создаем семафор
int j,n,i=0;
key_t key;
if((key = ftok("temp",3)) < 0){
perror("Can\'t generate key");
return 1;
}
int semid = semget(key, 4, 0666 | IPC_CREAT );
if (semid < 0){
perror("semget");
return 1;}
struct sembuf s_red[2] = {0, -1, IPC_NOWAIT, 1, 1, IPC_NOWAIT};
struct sembuf s_green[2] = {0, 1, IPC_NOWAIT, 1, -1, IPC_NOWAIT};
struct sembuf s_wait[2] = {0, 0, 0, 1, 0, 0};
struct sembuf s_readed = {2, 0, 0};
struct sembuf s_lock = {2, 1, IPC_NOWAIT};
struct sembuf s_unlock = {2, -1, IPC_NOWAIT};
union semun arg;
arg.val = 0;
semctl(semid, 0, SETVAL, arg);
arg.val = 1;
semctl(semid, 1, SETVAL, arg);
arg.val = 0;
semctl(semid, 2, SETVAL, arg);
// создаем два процесса
for (j=0; j<2; j++) {
switch (chpid [j] = fork ()) {
case -1:
printf ("Fork call error\n");
return 1;
case 0:
//child
cact.sa_flags = SA_SIGINFO;
cact.sa_sigaction = (void *) c_action;
sigaction (SIGUSR1, &cact, NULL);
printf("child #%d\n",getpid());
while (i <= 1000) {
// ожидаем разрешения
if ((start)&&
(semop( semid, &s_readed, 1)==0)&&
(semop( semid, &s_wait[j], 1)==0))
{
lseek (fd, 0, SEEK_END);
i = semctl(semid, 3, GETVAL);
if (i==1000)break;
for (n=0;n<100;n++){
gettimeofday(&c_time,NULL);
sprintf (str,"%4d #%5d :%6d\n", i+n+1,
getpid (), c_time.tv_usec);
write(fd,str,LEN);
}
i+=n;
arg.val = i;
semctl(semid, 3, SETVAL, arg);
// переключаем поток
if (j==0) semop( semid, &s_green, 2);
else semop( semid, &s_red, 2);
}
}
return 0;
}
}
printf("father #%d\n",getpid());
//father
kill (chpid [0], SIGUSR1);
kill (chpid [1], SIGUSR1);
i=0;
while (i < 1000) {
sleep(1);
// ожидаем разрешения
j=semctl(semid, 3, GETVAL);
if( (j>i+75)||(j==1000))
{
// блокируем
semop( semid, &s_lock, 1);
// читаем
lseek (fd, i*LEN, SEEK_SET);
for (n=0;n<75;n++){
if (i+n ==1000) break;
read(fd,str,LEN);
printf ("%s", str);
}
i+=n;
// разблокируем
semop( semid, &s_unlock, 1);
}
}
close(fd);
semctl(semid, 0, IPC_RMID);
return 0;
}
void c_action (int sig)
{
start = 1;
printf("action #%d\n",getpid());
}
Скриншоты выполнения программы: