СОДЕРЖАНИЕ
ВВЕДЕНИЕ
Анализ задания и разработка алгоритма
Теоретические сведения
Листинг программы
Тестирование
ВЫВОДЫ
ЛИТЕРАТУРА
ВВЕДЕНИЕ
Целью выполнения работы является закрепление знаний умений и навыков в области взаимодействия модулей, использования системных вызовов и библиотечных функций управления процессами и файлами современных операционных систем для создания системных и пользовательских программ, процедур и функций на примере ОС семейства UNIX/Linux. В ходе выполнения работы студенту необходимо продемонстрировать знания функций, алгоритмов, механизмов управления процессами, разделяемыми ресурсами, файлами, вводом-выводом.
Процесс — понятие, которое определяется по-разному. Это может быть — “упорядоченный набор команд и принадлежащих ему ресурсов”. С точки зрения ОС Unix процесс — это объект, зарегистрированный в специальной таблице процессов.
Телом процесса называется набор команд и данных, которыми оперирует процесс.
Контекст процесса — атрибут, который присутствует практически во всех ОС, в разных ОС он может называться по-разному. Контексты всех процессов размещаются в адресном пространстве ОС и содержат оперативную информацию о состоянии процесса и текущую информацию, связанную с процессом и его запуском.
1 АНАЛИЗ ЗАДАНИЯ И РАЗРАБОТКА АЛГОРИТМА
По заданию согласно варианта по списку необходимо организовать копирование содержимого из Файла 1 в остальные файлы (1->2, 1->3, 1->4).
Основные принципы по которым будет создаваться программа:
Будут созданы 4-е процесса, а именно 1-ый процесс породит 2-ый процесс, 1-ый процесс, в свою очередь породит 3-ий процесс, 1-ый процесс породит 4-тый процесс.
Каждый процесс будет иметь файл с соответствующими именами – file1, file2, file3, file4.
Процессы будут обмениваться через разделяемую память и временный файл.
Обмен содержимым файлов будет происходить по сигналу, семафорам и обмену сообщениями.
Процессы Process1 и Process4 обмениваются пользовательскими сигналами, по которым выполняется запись процессом Process1 во временный файл Temp file, после чего Process4 считывает из него данные, удаляет временный файл, затем записывает информацию в File4, ждет завершения обмена между процессами Process2, Process3, закрывает разделяемую память и уничтожает всю группу процессов.
Процессы Process1 и Process2 взаимодействуют с помощью семафоров. Process1 записывает в разделяемую память содержимое файла File1, после этого по семафору Process2 считывает из памяти данные и пишет в File2.
Процессы Process2 и Process3 взаимодействуют с помощью очереди сообщений. Когда данные уже записаны процессом Process2 в File2, он отсылает сообщение своему потомку, после чего Process3 считывает из разделяемой памяти данные, пишет в свой файл File3, отсылает сообщение назад и завершается, после чего закрывается и его родитель Process2.
Рис.1 Схема взаимодействия процессов
2 ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
С использованием функций в языке СИ связаны три понятия - определение функции (описание действий, выполняемых функцией), объявление функции (задание формы обращения к функции) и вызов функции.
Определение функции задает тип возвращаемого значения, имя функции, типы и число формальных параметров, а также объявления переменных и операторы, называемые телом функции, и определяющие действие функции. В определении функции также может быть задан класс памяти.
Функция fork:
int fork ( )
Вызов fork приводит к созданию нового процесса (порожденного процесса) - точной копии процесса, сделавшего вызов (родительского процесса). Точнее, порожденный процесс наследует у родительского процесса следующие характеристики:
Окружение.
Флаг "закрыть при выполнении вызова exec"
Способы обработки сигналов (то есть SIG_DFL, SIG_IGN, SIG_HOLD, адреса функций обработки сигналов).
Разрешение переустанавливать действующий идентификатор пользователя.
Разрешение переустанавливать действующий идентификатор группы.
Состояние профилирования (включено/выключено).
Значение поправки к приоритету.
Все присоединенные разделяемые сегменты памяти.
Идентификатор группы процессов.
Идентификатор группы терминала.
Текущий рабочий каталог.
Корневой каталог.
Маска режима создания файлов.
Ограничение на размер файла.
Порожденный процесс отличается от родительского процесса следующим:
Порожденный процесс имеет свой уникальный идентификатор процесса.
Порожденный процесс имеет иной идентификатор родительского процесса, равный идентификатору процесса, его породившего.
Порожденный процесс имеет свои собственные копии родительских дескрипторов файлов. Каждый дескриптор файла порожденного процесса разделяет с соответствующим родительским дескриптором файла общий указатель текущей позиции в файле.
Все semadj значения сбрасываются.
Порожденный процесс не наследует у родительского процесса признаков удержания в памяти сегмента команд, данных или всего процесса целиком.
Обнуляются счетчики времени, потраченного для обслуживания этого процесса (tms_utime, tms_stime, tms_cutime, tms_cstime). Отменяется запрос к будильнику.
3 ЛИСТИНГ ПРОГРАММЫ
Программа состоит из главного модуля rgr.c:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#define SHMKEY 5
#define SEMKEY 5
#define K 32
#define Count 4
#define InitVal {1,0,0,0}
#define MSGKEY 5
#define InitT 3
void creat_mem(void);
void creat_sem(void);
void prss1(void);
void prss2(void);
void prss3(void);
void prss4(void);
int pid1; int pid2; int pid3; int pid4; int pid; int ppid;
int fd; int st;
extern int p14(int), p41(int);
//mem
int shmid;
int *pint;
char *addr;
//sem
int semid;
short initarray[Count] = InitVal;
struct sembuf p, v;
//message:
int prnum;
int msgid;
long nextT;
struct {
long mtype;
int Data;
} Message;
int main(void)
{
remove("file2");
remove("file3");
remove("file4");
creat_mem();
creat_sem();
pid1 = getpid();
pid = fork();
if (!pid) prss2();
else prss1();
sleep(2);
wait(&st);
}
void creat_mem(void)
{
printf("--- func creat_mem(): memory creating: %dbytes --- pid=%d\n", K, getpid());
shmid = shmget(SHMKEY, 1*K, 0777|IPC_CREAT);
addr = shmat(shmid, 0, 0);
pint = (int *) addr;
}
void creat_sem(void)
{
printf("--- func creat_sem(): semaphor creating: --- pid=%d\n", getpid());
semid = semget(SEMKEY, Count, 0777|IPC_CREAT);
semctl(semid, Count, SETALL, initarray);
p.sem_op = -1;
p.sem_flg = SEM_UNDO;
v.sem_op = 1;
v.sem_flg = SEM_UNDO;
}
void creat_mesg(void)
{
msgid = msgget(MSGKEY, 0666|IPC_CREAT);
msgsnd(msgid, (struct msgbuf *) &Message, 8, 0);
}
void prss1(void)
{
int i;
char buf[32] = " ";
prnum = 1;
p.sem_num = 0;
v.sem_num = 1;
ppid = getppid();
printf(" =I= prss%d, pid = %d, parent: %d\n", prnum, pid1, ppid);
pid = fork();
if (!pid) prss4();
else
{
fd = open("file1", O_RDONLY);
read(fd,buf,strlen(buf));
close(fd);
printf("I: reading from FILE1:\t%s\n",buf);
signal(SIGUSR2, p41);
sleep(1);//ojidanie priema signala ot prssa4
kill(pid1+2,SIGUSR1);
printf("================== prss1: writing to memory\n");
for(i = 0; i <= 31; ++i) pint[i] = buf[i];
semop(semid, &p, 1);
semop(semid, &v, 1);
sleep(2);
wait(&st);
wait(&st);
printf(" =I= __eto konec prssa%d\n", prnum);
}
}
void prss2(void)
{
int i;
char buf_2[32]=" ";
prnum = 2;
p.sem_num = 1;
pid2 = getpid();
ppid = getppid();
printf(" =II= prss%d, pid = %d, parent: %d\n", prnum, pid2, ppid);
creat("file2",fd);
pid = fork();
if (!pid) prss3();
else
{
semop(semid, &p, 1);
printf("================== prss%d: file2 editing /Semaphor/\n", prnum);
fd = open("file2", O_WRONLY);
for(i = 0; i <= 31; ++i) buf_2[i] = pint[i];
write(fd,buf_2,strlen(buf_2));
printf("II: writing to FILE2:\t%s\n",buf_2);
printf("--- func creat_mesg(): message creating: --- pid=%d\n", pid2);
Message.mtype = InitT;
Message.Data=3;
creat_mesg();
printf(" =II= __eto konec prssa%d\n", prnum);
fclose(fd);
}
}
void prss3(void)
{
int i;
char buf_3[32]=" ";
prnum = 3;
pid3 = getpid();
ppid = getppid();
printf(" =III= prss%d, pid = %d, parent: %d\n", prnum, pid3, ppid);
creat("file3",fd);
msgrcv(msgid, (struct msgbuf *) (&Message), 8, prnum, 0);
if (Message.Data==3)
{
printf("================== prss%d: file3 editing /Message/\n", prnum);
fd = open("file3", O_WRONLY);
for(i = 0; i <= 31; ++i) buf_3[i] = pint[i];
write(fd,buf_3,strlen(buf_3));
printf("III: writing to FILE3:\t%s\n",buf_3);
printf(" =III= __eto konec prssa%d\n", prnum);
fclose(fd);
}
}
void prss4(void)
{
int i;
prnum = 4;
pid4 = getpid();
ppid = getppid();
printf(" =IV= prss%d, pid = %d, parent: %d\n", prnum, pid4, ppid);
creat("file4",fd);
signal(SIGUSR1, p14);
kill(pid1,SIGUSR2);
sleep(1);
printf(" =IV= __eto konec prssa%d\n", prnum);
shmctl(shmid,IPC_RMID,0);
printf("================== prss4: memory closed\n");
kill(0,SIGKILL);
}
int p14(int signum) //2-oj sig
{
char temp_buf4[32]=" ";
signal(SIGUSR1, p14);
printf("***SIGUSR1*** : prss 4 (%d) has got a signal from prss 1 (%d)\n",pid4,pid1);
fd = open("temp_file", O_RDONLY);
read(fd,temp_buf4,strlen(temp_buf4));
close(fd);
creat("file4",fd);
printf("* *SIGUSR1* * : writing from temp_file to file4\n");
fd = open("file4", O_WRONLY);
write(fd,temp_buf4,strlen(temp_buf4));
close(fd);
printf("IV: writing to FILE4:\t%s\n",temp_buf4);
remove("temp_file");
printf("* *SIGUSR1* * : temp_file was removed\n");
printf("***SIGUSR1*** : end\n");
}
int p41(int signum) //1-ij sig
{
char temp_buf1[32]=" ";
signal(SIGUSR2, p41);
printf("***SIGUSR2*** prss 1 (%d) has got a signal from prss 4 (%d)\n",pid1,pid1+2);
fd = open("file1", O_RDONLY);
read(fd,temp_buf1,strlen(temp_buf1));
close(fd);
creat("temp_file",fd);
printf("* *SIGUSR2* * : temp_file was created\n");
fd = open("temp_file", O_WRONLY);
write(fd,temp_buf1,strlen(temp_buf1));
close(fd);
printf("***SIGUSR2*** : end\n");
}
4 ТЕСТИРОВАНИЕ
Результат выполнения программы в консоли:
yuna@YunieHost:/media/8_Gb_hard_ONPU/LINUX/rgr 28march$ ./rgr
--- func creat_mem(): memory creating: 32bytes --- pid=6798
--- func creat_sem(): semaphor creating: --- pid=6798
=II= prss2, pid = 6799, parent: 6798
=I= prss1, pid = 6798, parent: 6655
=III= prss3, pid = 6801, parent: 6799
=IV= prss4, pid = 6800, parent: 6798
I: reading from FILE1: << RGR sPO by yuna 18.05.2008 >>
***SIGUSR2*** prss 1 (6798) has got a signal from prss 4 (6800)
* *SIGUSR2* * : temp_file was created
***SIGUSR2*** : end
================== prss1: writing to memory
================== prss2: file2 editing /Semaphor/
II: writing to FILE2: << RGR sPO by yuna 18.05.2008 >>
--- func creat_mesg(): message creating: --- pid=6799
=II= __eto konec prssa2
***SIGUSR1*** : prss 4 (6800) has got a signal from prss 1 (6798)
================== prss3: file3 editing /Message/
III: writing to FILE3: << RGR sPO by yuna 18.05.2008 >>
=III= __eto konec prssa3
* *SIGUSR1* * : writing from temp_file to file4
IV: writing to FILE4: << RGR sPO by yuna 18.05.2008 >>
* *SIGUSR1* * : temp_file was removed
***SIGUSR1*** : end
=IV= __eto konec prssa4
================== prss4: memory closed
Killed
Рис.2 Результат работы программы (содержимое из file1 было скопировано в остальные файлы)
Следовательно, программа работает корректно и поставленная на данную расчетно-графическую работу задача была решена.
ВЫВОДЫ
В данной работе частично описана структура системы UNIX, взаимоотношения между процессами, выполняющимися в режиме задачи и в режиме ядра. Процессы выполняются в режиме задачи или в режиме ядра, в котором они пользуются услугами системы благодаря наличию набора обращений к операционной системе.
Архитектура системы поддерживает такой стиль программирования, при котором из небольших программ, выполняющих только отдельные функции, но хорошо, составляются более сложные программы, использующие механизм каналов и переназначение ввода-вывода.
Обращения к операционной системе позволяют процессам производить операции, которые иначе не выполняются. В дополнение к обработке подобных обращений ядро операционной системы осуществляет общие учетные операции, управляет планированием процессов, распределением памяти и защитой процессов в оперативной памяти, обслуживает прерывания, управляет файлами и устройствами и обрабатывает особые ситуации, возникающие в системе.
В функции ядра системы UNIX намеренно не включены многие функции, являющиеся частью других операционных систем, поскольку набор обращений к системе позволяет процессам выполнять все необходимые операции на пользовательском уровне.
ЛИТЕРАТУРА
Дж. Такет (мл.), С.Барнет. Использование Linux/ Специальное издание.: 5-е изд.: Пер. с англ.: Уч.пос. – М.: Издательский дом «Вильямс», 2000. – 784 с.
Максимальная защита Linux. Искусство настройки.: Пер. с англ./ под.ред. Дж.Рея – СПб.: ООО «ДиаСофтЮП», 2002. – 752 с.
Браун С. Операционная система UNIX - М.: Мир, 1986 - 463 с.