Министерствообразования Республики Беларусь
Учреждениеобразования
Белорусский государственный университет
информатики и радиоэлектроники
Кафедра программногообеспечения
информационныхтехнологий
Алексеев Игорь Геннадиевич,
Бранцевич Петр Юльянович
“Теориявычислительных процессов и структур”
учебно-методическое пособие для студентовспециальности
«Программноеобеспечение информационных технологий»
дневной формыобучения
Минск 2004
УДК 004.04 (075.8)
ББК 32.973 я 73
А47
Рецензент:
доцент Института информационных технологий
канд. техн. наук В.Н. Мухаметов
А47Алексеев И.Г. Учебно-методическоепособие Теория вычислительных процессов и систем: для студ. спец.«Программное обеспечение информационных технологий»/И.Г Алексеев, П.Ю. Бранцевич– Мн.: БГУИР, 2004. –54 с.
ISBN 985-444-№
В пособии рассмотреныосновные команды операционной системы UNIX, предназначенные для работыс файлами и каталогами, а также для создания процессов и организациивзаимодействия между ними. Даны структуры лабораторных работ по курсу «ТВПиС»
УДК 004.04(075.8)
ББК 32.973я 73
А47
ISBN985-444-387-6 © Алексеев И.Г, Бранцевич П.Ю 2004
© БГУИР, 2004
СОДЕРЖАНИЕ
1. ОСНОВНЫЕ КомандыОС UNIX… 4
2. Лабораторныеработы… 6
Лабораторнаяработа № 1 Работа с файламии каталогами ОС UNIX… 6
Лабораторнаяработа № 2 Создание процессов … 17
Лабораторнаяработа № 3 Взаимодействие процессов… 24
Лабораторнаяработа № 4 Сигналы… 31
Лабораторнаяработа № 5 Использование каналов… 40
Лабораторнаяработа № 6 Работа с несколькими каналами… 46
Лабораторнаяработа № 7 Работа с использованием неименованных
каналов… 52
Литература… 53
1. Основные команды ос unix
Вход в систему ивыход
В ответ на приглашение системыввести Logon вводим: sxtxx, например s5t03, где 5 – номер Вашей группы, а 03 –Ваш порядковый номер в группе. Затем после входа в систему устанавливаем с помощью команды passwd свой пароль длиной не менее 6 символов. Не забывайтесвой логин и пароль! Пароль нельзя восстановить!
Пароль взашифрованном виде находится в каталоге ./etс в файле shadowи для его сброса необходимо удалить набор символов после имени пользователямежду двоеточиями. Например, пользователь stud1, запись в файле shadow:
stud1:gdwiefu@#@#$%66reHHrrnCvcn:12060:………
после удаления пароля запись должна быть следующая:
stud1::12060:………
Выход из системы можно осуществить по команде exit
Рабочие каталоги ифайлы
Ваш рабочийкаталог: /home/sxtxx, где xи xx – номер группы ипорядковый номер студента в группе.
Включаемые файлы типа: stdio.h, stdlib.h и т.п. находятся в каталоге: /usr/include/
Работа с каталогами ифайлами
Для выводасодержимого текущего каталога можно использовать команду: dirили ls, для изменения текущего каталога – команду: cd.
Для выводаполного имени текущего каталога можноиспользовать команду: pwd, для создания или удалениякаталога – команды: mkdirи rmdir.
Для вывода натерминал содержимого файла можно использовать команду: cat имя_файла,например: catprog.txt.
Для вызовафайл-менеджера типа Norton`анабираем: mc (вызов оболочки файл-менеджера MidnightCommander) и далее работаем сего меню.
Для вызоватекстового редактора набираем: joe или joe имя_создаваемого_или_редактируемого_файла. В самомредакторе практически все команды начинаются с последовательности ctrl-k, и нажатия нужного символа.Например, ctrl-k h выведет справку по основным командам редактора, а ctrl-kx завершит работу редактора с сохранением редактируемогофайла.
Работа с программамии процессами
Запускпрограммы на выполнение:
./имя_программынапример: ./prog1.exe
Для компиляциипрограмм на С/С++ вызываем компилятор:
cc имя_входного_файла – оимя_выходного_файла или:
gcc имя_входного_файла – оимя_выходного_файла,
где имя_входного_файла обязательно должно быть с расширением*.с или *.cpp, аимя_выходного_файла может быть любым (желательно совпадать с именем входногофайла, кроме расширения).
Например: ccmyprog1.c–omyprog1
или
gccmyprog1.c –o myprog1
Для вывода списка запущенныхпроцессов можно использовать команду:
ps, например: ps –x выведет список всех запущенных процессов.
Для снятиязадачи (процесса) можно использовать команду: killpid_процесса,предварительно узнав его pidкомандой ps.
В каталоге ./proc находятся сведения обо всехзапущенных процессах в системе, их состоянии, распределении памяти и т.д.
Типовой вид каталога:
./proc/1081/……..,
./proc/1085/………,где 1081 и 1082 соответственно pidзапущенных процессов в системе.
Справку по командам системы или по языку С можно получить покоманде:
man имя_команды, например: manls
2. Лабораторные работы
Лабораторная работа№1
Работа с файлами и каталогамиОС UNIX
Цель работы – изучить основныекоманды ОС UNIX для работы с файлами и каталогами.
Теоретическая часть
Длявыполнения операций записи и чтения данных в существующем файле его следует открыть при помощисистемного вызова open. Ниже приведено описание этоговызова:
# include
# include
# include
int open (const char *pathname, int flags,[mode_t mode]);
Первый аргумент, pathname, является указателем на строку маршрутного имениоткрываемого файла. Значение pathnameможет быть абсолютным путём,например: /usr / keith / junk.Данный путь задаёт положение файла по отношению к корневому каталогу. Аргумент pathnameможет также бытьотносительным путём, задающим маршрут от текущего каталога к файлу, например: keith / junk или просто junk. В последнем случае программаоткроет файл junkвтекущем каталоге. В общем случае, если один из аргументов системного вызова илибиблиотечной процедуры – имя файла, то в качестве него можно задать любоедопустимое маршрутное имя файла UNIX.
Второй аргумент системного вызоваopen — flags — имеетцелочисленный тип и определяет метод доступа. Параметр flags принимает одно иззначений, заданных постоянными в заголовочном файле при помощи директивы препроцессора #define ( fcnt1 является сокращением от filecontrol — «управление файлом»). В файле определены три постоянных:
O_RDONLY– открыть файл только для чтения,
O_WRONLY – открыть файл только для записи,
O_RDWR – открыть файл для чтения и записи.
В случае успешного завершениявызова openи открытия файла возвращаемоевызовом openзначениебудет содержать неотрицательное целое число – дескриптор файла. В случае ошибкивызов open возвращает вместо дескриптора файла значение–1. Это может произойти, например, если файл не существует.
Третий параметр mode, является необязательным, он используется только вместес флагом O_CREAT.
Следующий фрагмент программыоткрывает файл junkдлячтения и записи и проверяет, не возникает ли при этом ошибка. Этот последниймомент особенно важен: имеет смысл устанавливать проверку ошибок во всепрограммы, которые используют системные вызовы, поскольку каким бы простым нибыло приложение, иногда может произойти сбой. В приведенном ниже примереиспользуются библиотечные процедуры printfдлявывода сообщения и exit– длязавершения процесса:
# include /* Длявызоваexit */
# include
char workfile=”junk”; /Задатьимярабочегофайла*/
main()
{
intfiledes;
/* Открыть файл, используя постоянную O_RDWR из */
/* Файл открывается для чтения / записи */
if ((filedes=open(workfile, O_RDWR)) = = -1)
{
printf (“Невозможно открыть %sn”, workfile);
exit (1); /* Выходпо ошибке */
}
/* Остальная программа */
exit (0); /* Нормальный выход */
}
Вызов openможет использоваться для создания файла, например:
filedes = open(“/tmp/newfile”, O_WRONLY | O_CREAT, 0644);
Здесь объединены флаги O_CREAT иO_WRONLY, задающие создание файла /tmp/newfile при помощи вызова open. Если /tmp/newfile не существует, тобудет создан файл нулевой длины с таким именем и открыт только для записи.
Параметр modeсодержит число, определяющее права доступа к файлу, указывающие, кто из пользователей системыможет осуществлять чтение, запись или выполнение файла. Пользователь, создавшийфайл, может выполнять чтение из файла и запись в него. Остальные пользователибудут иметь доступ только для чтения файла.
Следующая программа создаёт файл newfileв текущем каталоге:
# include
# include
#definePERMS 0644 /* Права доступа при открытии с O_CREAT*/
char *filename=”newfile”;
main()
{
int filedes;
if ((filedes=open (filename, O_RDWR | O_CREAT, PERMS)) = = -1)
{
printf (“Невозможно открыть %sn”,filename);
exit (1); /* Выходпо ошибке */
}
/* Остальная программа */
exit (0);
}
Другой способ создания файлазаключается в использовании системного вызова creat. Так же, как и вызов open, он возвращает либо ненулевой дескриптор файла, либо –1в случае ошибки. Если файл успешно создан, то возвращаемое значение являетсядескриптором этого файла, открытого для записи. Вызовcreatосуществляетсятак:
# include
# include
# include
int creat (const char *pathname, mode_t mode);
Первый параметр pathname указывает намаршрутное имя файла UNIX,определяющее имя создаваемого файла и путь к нему. Так же, как и в случаевызова open, параметр mode задаёт правадоступа. При этом, если файл существует, то второй параметр также игнорируется.Тем не менее, в отличие от вызова open, в результате вызоваcreat файл всегда будет усечён до нулевой длины. Примериспользования вызова creat:
filedes = creat (“/tmp/newfile”, 0644);
что эквивалентно вызову:
filedes = open (“/tmp/newfile”, O_WRONLY |O_CREAT | O_TRUNC, 0644);
Следует отметить, что вызов creat всегда открывает файл только для записи. Например,программа не может создать файл при помощиcreat, записать в него данные, затем вернуться назад ипопытаться прочитать данные из файла, если предварительно не закроет его и неоткроет снова при помощи вызова open.
Библиотечная процедура fopen является эквивалентом вызова open:
#include
FILE *fopen (const char *filename, const char *type);
Процедура fopenоткрывает файл, заданный параметром filename, и связывает сним структуру FILE. Вслучае успешного завершения процедура fopen возвращаетуказатель на структуру FILE,идентифицирующую открытый файл; объект FILE * также часто называют открытым потоком ввода / вывода (эта структура FILE является элементом внутреннейтаблицы). В случае неудачи процедура fopen возвращает нулевойуказатель NULL. При этом,так же, как и для open, переменная errno будет содержать код ошибки, указывающий на её причину.
Второй параметр процедуры fopen указывает на строку, определяющую режим доступа. Онаможет принимать следующие основные значения:
r — открыть файл filenameтолько для чтения (если файл не существует, то процедура fopenвернёт нулевой указатель NULL);
w — создать файл filename иоткрыть его только для записи (если файл не существует, то он будет усечён донулевой длины);
а — открыть файл filename только для записи, все данные будут добавляться вконец файла (если файл не существует, он создаётся).
Следующий пример программыпоказывает использование процедуры fopen. При этом, еслифайл indata существует, то он открывается для чтения, а файл outdata создаётся (или усекается до нулевой длины, если онсуществует). Процедура fatal предназначена для выводасообщения об ошибке. Она просто передаёт свой аргумент процедуре perror, а затем вызывается exit длязавершения работы программы:
#include
char *inname = “indata”;
char *outname = “outdata”;
main()
{
FILE *inf, *outf;
if ((inf = fopen (inname, “r”)) = = NULL)
fatal (“Невозможно открыть входной файл”);
if ((outf = fopen (outname, “w”)) = = NULL)
fatal (“Невозможно открыть выходной файл”);
/* Выполняются какие-либо действия */
exit (0);
}
Основные процедуры для вводастрок называются gets иfgets:
# include
char *gets (char *buf);
char *fgets (char *buf, int nsize, FILE *inf);
Процедура gets считывает последовательность символов из потокастандартного ввода (stdin), помещая все символы в буфер,на который указывает аргумент buf. Символы считываютсядо тех пор, пока не встретится символ перевода строки или конца файла. Символперевода строки newline отбрасывается, и вместо негов буфер помещается нулевой символ, образуя завершённую строку. В случаевозникновения ошибки или при достижении конца файла возвращается значение NULL.
Процедура fgetsявляется обобщённой версией процедуры gets. Она считывает из потока infв буфер bufдо тех пор, пока не будет считано nsize-1 символов или невстретится раньше символ перевода строки newline, или не будет достигнут конец файла. В процедуре fgets символы перевода строки newline неотбрасываются, а помещаются в конец буфера (это позволяет вызывающей функцииопределить, в результате чего произошёл возврат из процедуры fgets). Как и процедура gets, процедура fgets возвращает указатель на буфер buf вслучае успеха и NULL –в противном случае.
Следующая процедура yesno использует процедуру fgets дляполучения положительного или отрицательного ответа от пользователя, она такжевызывает макрос isspace для пропуска пробельныхсимволов в строке ответа:
# include
# include
#define YES 1
#define NO 0
#define ANSWSZ 80
static char *pdefault = “Наберите‘y’ (YES), или‘n’ (NO)”;
static char *error = “Неопределённыйответ”;
int yesno (char *prompt)
{
char buf [ANSWSZ], *p_use, *p;
/* Выводит приглашение, если оно не равно NULL
· pdefault */
p_use = (prompt != NULL)? prompt: pdefault;
/*Бесконечный цикл до получения правильного ответа */
for (;;)
{
/* Выводит приглашение */
printf (“%s>”, p_use );
if (fgets (buf, ANSWSZ, stdin) = = NULL)
returnEOF;
/* Удаляет пробельные символы */
for (p = buf; isspace (*p); p++)
;
switch (*p)
{
case ‘Y’:
case ‘y’:
return (YES);
case ‘N’:
case ‘n’:
return (NO);
default:
printf (“%s”, error);
}
}
}
Обратными процедурами для gets и fgets будутсоответственно процедуры puts и fputs:
# include
int puts (const char *string);
int fputs (const char *string, FILE *outf);
Процедура puts записывает все символы (кромезавершающего нулевого символа) из строки string на стандартныйвывод (stdout). Процедура fputs записывает строку stringв поток outf. Дляобеспечения совместимости со старыми версиями системы процедура putsдобавляет в конце символперевода строки, процедура же fputs не делает этого.Обе функции возвращают в случае ошибки значение EOF.
Для осуществленияформатированного вывода используются процедуры printf и fprintf:
# include
int printf (const char *fmt, arg1, arg2 …argn);
int fprintf (FILE *outf, const char *fmt, arg1,arg2 … argn);
Каждая из этих процедур получает строку формата вывода fmt и переменное число аргументов произвольного типа,используемых для формирования выходной строки вывода. В выходную строкувыводится информация из параметров arg1 … argn согласно формату, заданному аргументом fmt. В случае процедуры printf эта строка затемкопируется в stdout. Процедура fprintf направляет выходную строку в файл outf.
Для каждого из аргументов arg1 … argn должна быть заданасвоя спецификация формата, которая указывает тип соответствующего аргумента испособ его преобразования в выходную последовательность символов ASCII.
Рассмотримпример, демонстрирующий использование формата процедуры printf вдвух простых случаях:
int iarg = 34;
…
printf (“Hello, world!”);
printf (“Значение переменной iarg равно %dn”, iarg);
Результат:
Hello, world!
Значение переменной iarg равно 34
Возможные типы спецификаций(кодов) формата:
Целочисленные форматы:
%d — общеупотребительный код формата длязначений типа int. Если значение являетсяотрицательным, то будет автоматически добавлен знак минуса;
%u — тип unsignedint, выводится в десятичной форме;
%o — тип unsignedint, выводится как восьмеричноечисло без знака;
%x — тип unsignedint, выводится как шестнадцатеричноечисло без знака;
%ld — тип long сознаком, выводится в десятичной форме.
Можно также использоватьспецификации %lo, %lu, %x.
Форматы вещественных чисел:
%f — тип floatили double, выводится встандартной десятичной форме;
%е — тип floatили double, выводится вэкспоненциальной форме (для обозначения экспоненты будет использоваться символе);
%g — объединение спецификаций %e и %f — аргумент имеет тип floatили double взависимости от величины числа, оно будет выводиться либо в обычном формате, либов формате экспоненциальной записи.
Форматирование строк и символов:
%c — тип char,выводится без изменений, даже если является «непечатаемым» символом (численноезначение символа можно вывести, используя код формата для целых чисел, этоможет понадобиться при невозможности отображения символа на терминале);
%s — соответствующий аргумент считаетсястрокой ( указателем на массив символов). Содержимое строки передаётся дословнов выходной поток, строка должна заканчиваться нулевым символом.
Спецификации формата могут такжевключать информацию о минимальной ширинеполя, в котором выводится аргумент, и точности.В случае целочисленного аргумента под точностью понимается максимальное числовыводимых цифр. Если аргумент имеет тип floatили double, то точностьзадаёт число цифр после десятичной точки. Для строчного аргумента этот параметропределяет число символов, которые будут взяты из строки. Например, могутиспользоваться такие записи: %10.5d; %.5f; %10s; %-30s.
Функция fprintfможет использоваться для вывода диагностических ошибок:
#include
#include
int notfound (const char *progname, const char*filename)
{ fprintf (stderr, “%s: файл%s ненайден”,progname,filename);
exit(1); }
Для опроса состояния структуры FILE существует ряд простыхфункций. Однаизних — функцияfeof:
#include
int feof (FILE *stream);
Функция feofявляется предикатом, возвращающим ненулевое значение, если для потока stream достигнут конец файла. Возврат нулевого значенияпросто означает, что этого ещё не произошло.
Функцияmain:
int main( int argc, char *argv[ ] [, char*envp[ ] ] );
Данное объявление позволяет удобно передавать аргументыкомандной строки ипеременные окружения. Определение аргументов:
argc — количество аргументов, которые содержатся в argv[](всегда больше либо равен 1);
argv — в массиве строкипредставляют собой параметры из командной строки, введенные пользователемпрограммы. По соглашению, argv [0] – это команда,которой была запущена программа, argv[1] – первый параметр из командной строки и так далее до argv [argc] – элемент,всегда равный NULL;
envp — массив envp общеерасширение, существующее во многих UNIX® системах. Это массив строк, которые представляют собойпеременные окружения. Массив заканчивается значением NULL.
Следующий пример показывает, какиспользовать argc, argv и envp в функции main:#include #include void main( int argc, char * argv [], char *envp[] ){ int iNumberLines = 0; /* По умолчанию нет аргументов */ if( argc == 2 && strcmp(argv[1], "/n" ) == 0 ) iNumberLines = 1; /* Проходим список строк пока не NULL */ for( int i = 0; envp[i] != NULL; ++i ) { if( iNumberLines ) cout }}Для работы с каталогами существуют системные вызовы: int mkdir (const char *pathname, mode_t mode) – создание нового каталога, int rmdir(const char *pathname) – удаление каталога.Первый параметр – имя создаваемого каталога, второй – права доступа: retval=mkdir(“/home/s1/t12/alex”,0777); retval=rmdir(“/home/s1/t12/alex”);Заметим, что вызов rmdir(“/home/s1/t12/alex”) будет успешен, только если удаляемый каталог пуст, т.е. содержит записи “точка” (. ) и “двойная точка” (..). Для открытия или закрытия каталогов существуют вызовы: #include DIR *opendir (const char *dirname); int closedir( DIR *dirptr); Пример вызова: if ((d= opendir (“/home/s1”))==NULL) /* ошибка открытия */ exit(1);Передаваемый вызову opendir параметр является именем открываемого каталога. При успешном открытии каталога dirname вызов opendir возвращает указатель на переменную типа DIR. Определение типа DIR, представляющего дескриптор открытого каталога, находится в заголовочном файле “dirent.h”. В частности, поле name структуры DIR содержит запись имени файла, содержащегося в каталоге: DIR *d; ff=d->name; printf(“%sn”, ff);Указатель позиции ввода/вывода после открытия каталога устанавливается на первую запись каталога. При неуспешном открытии функция возвращает значение NULL. После завершения работы с каталогом необходимо его закрыть вызовом closedir. Для чтения записей каталога существует вызов: struct dirent *readdir(DIR *dirptr); Пример вызова: DIR *dp; struct dirent *d; d=readdir