Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Процессы и потоки в ОС LinuxСодержание книги
Поиск на нашем сайте Цель работы – исследовать методы создания процессов в ОС Linux, основные функции создания и управления процессами, обмен данными между процессами.
Теоретическая часть В ОС Linux для создания процессов используется системный вызов fork(): #include <sys/types.h> #include <unistd.h> pid_t fork (void); В результате успешного вызова fork() ядро создаёт новый процесс, который является почти точной копией вызывающего процесса. Другими словами, новый процесс выполняет копию той же программы, что и создавший его процесс, при этом все его объекты данных имеют те же самые значения, что и в вызывающем процессе. Созданный процесс называется дочерним процессом, а процесс, осуществивший вызов fork(), называется родительским. После вызова родительский процесс и его вновь созданный потомок выполняются одновременно, при этом оба процесса продолжают выполнение с оператора, который следует сразу же за вызовом fork(). Процессы выполняются в разных адресных пространствах, поэтому прямой доступ к переменным одного процесса из другого процесса невозможен. Следующая короткая программа более наглядно показывает работу вызова fork() и использование процесса: #include <stdio.h> #include <unistd.h> Int main () { pid_t pid; /* идентификатор процесса */ printf (“Пока всего один процесс\n”); pid = fork (); /* Создание нового процесса */ printf (“Уже два процесса\n”); if (pid = = 0) { printf (“Это Дочерний процесс его pid=%d\n”, getpid()); printf (“А pid его Родительского процесса=%d\n”, getppid()); } else if (pid > 0) printf (“Это Родительский процесс pid=%d\n”, getpid()); Else printf (“Ошибка вызова fork, потомок не создан\n”); } Для корректного завершения дочернего процесса в родительском процессе необходимо использовать функцию wait() или waitpid(): pid_t wait(int *status); Функция wait приостанавливает выполнение родительского процесса до тех пор, пока дочерний процесс не прекратит выполнение или до появления сигнала, который либо завершает текущий процесс, либо требует вызвать функцию-обработчик. Если дочерний процесс к моменту вызова функции уже завершился (так называемый «зомби»), то функция немедленно возвращается. Системные ресурсы, связанные с дочерним процессом, освобождаются. Функция waitpid приостанавливает выполнение родительского процесса до тех пор, пока дочерний процесс, указанный в параметре pid, не завершит выполнение, или пока не появится сигнал, который либо завершает родительский процесс, либо требует вызвать функцию-обработчик. Если указанный дочерний процесс к моменту вызова функции уже завершился (так называемый «зомби»), то функция немедленно возвращается. Системные ресурсы, связанные с дочерним процессом, освобождаются. Параметр pid может принимать несколько значений: pid<-1 означает, что нужно ждать любого дочернего процесса, чей идентификатор группы процессов равен абсолютному значению pid. pid=-1 означает ожидать любого дочернего процесса; функция wait ведет себя точно так же. pid =0 означает ожидать любого дочернего процесса, чей идентификатор группы процессов равен таковому у текущего процесса. pid>0 означает ожидать дочернего процесса, чем идентификатор равен pid. Значение options создается путем битовой операции ИЛИ над следующими константами: WNOHANG - означает вернуть управление немедленно, если ни один дочерний процесс не завершил выполнение. WUNTRACED -означает возвращать управление также для остановленных дочерних процессов, о чьем статусе еще не было сообщено. Каждый дочерний процесс при завершении работы посылает своему процессу-родителю специальный сигнал SIGCHLD, на который у всех процессов по умолчанию установлена реакция "игнорировать сигнал". Наличие такого сигнала совместно с системным вызовом waitpid() позволяет организовать асинхронный сбор информации о статусе завершившихся порожденных процессов процессом-родителем. Для перегрузки исполняемой программы можно использовать функции семейства exec. Основное отличие между разными функциями в семействе состоит в способе передачи параметров. int execl(char *pathname, char *arg0, arg1,..., argn, NULL); int execle(char *pathname, char *arg0, arg1,..., argn, NULL, char **envp); int execlp(char *pathname, char *arg0, arg1,..., argn, NULL); int execlpe(char *pathname, char *arg0, arg1,..., argn, NULL, char **envp); int execv(char *pathname, char *argv[]); int execve(char *pathname, char *argv[],char **envp); int execvp(char *pathname, char *argv[]); int execvpe(char *pathname, char *argv[],char **envp); Существует расширенная реализация понятия процесс, когда процесс представляет собой совокупность выделенных ему ресурсов и набора нитей исполнения. Нити(threads) или потокипроцесса разделяют его программный код, глобальные переменные и системные ресурсы, но каждая нить имеет собственный программный счетчик, свое содержимое регистров и свой стек. Все глобальные переменные доступны в любой из дочерних нитей. Каждая нить исполнения имеет в системе уникальный номер – идентификатор нити. Поскольку традиционный процесс в концепции нитей исполнения трактуется как процесс, содержащий единственную нить исполнения, мы можем узнать идентификатор этой нити и для любого обычного процесса. Для этого используется функция pthread_self(). Нить исполнения, создаваемую при рождении нового процесса, принято называть начальной или главной нитью исполнения этого процесса. Для создания нитей используется функция pthread_create: #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); Функция создает новую нить в которой выполняется функция пользователя start_routine,передавая ей в качестве аргумента параметр arg. Если требуется передать более одного параметра, они собираются в структуру, и передается адрес этой структуры.При удачном вызове функция pthread_create возвращает значение 0 и помещает идентификатор новой нити исполнения по адресу, на который указывает параметр thread. В случае ошибки возвращается положительное значение, которое определяет код ошибки, описанный в файле <errno.h>. Значение системной переменной errno при этом не устанавливается. Параметр attr служит для задания различных атрибутов создаваемой нити. Функция нити должна иметь заголовок вида: void * start_routine (void *) Завершение функции потока происходит если: · функция нити вызвала функцию pthread_exit(); · функция нити достигла точки выхода; · нить была досрочно завершена другой нитью. Функция pthread_join() используется для перевода нити в состояние ожидания: #include <pthread.h> int pthread_join (pthread_t thread, void **status_addr); Функция pthread_join() блокирует работу вызвавшей ее нити исполнения до завершения нити с идентификатором thread. После разблокирования в указатель, расположенный по адресу status_addr, заносится адрес, который вернул завершившийся thread либо при выходе из ассоциированной с ним функции, либо при выполнении функции pthread_exit(). Если нас не интересует, что вернула нам нить исполнения, в качестве этого параметра можно использовать значение NULL. Для компиляции программы с нитями необходимо подключить библиотеку pthread.lib следующим способом: Gcc 1.c –o 1.exe -lpthread Время в Linux отсчитывается в секундах, прошедшее с начала этой эпохи (00:00:00 UTC, 1 Января 1970 года). Для получения системного времени можно использовать следующие функции: #include <sys/time.h> time_t time (time_t *tt); int gettimeofday(struct timeval *tv, struct timezone *tz); struct timeval { long tv_sec; /* секунды */ long tv_usec; /* микросекунды */ };
Порядок выполнения работы 1. Изучить теоретическую часть работы. 2. Написать программу, создающую два дочерних процесса с использованием двух вызовов fork(). Родительский и два дочерних процесса должны выводить на экран свой pid и pid родительского процесса и текущее время в формате: часы: минуты: секунды: миллисекунды. Используя вызов system(), выполнить команду ps -x в родительском процессе. Найти свои процессы в списке запущенных процессов. 3. В основной программе создать 2 потока. После этого процесс-отец создает файл, записывает в него строки вида: N pid текущее время в формате: часы: минуты: секунды: миллисекунды (где N – номер выводимой строки) и выводит формируемые строки в левой половине экрана. Количество записываемых в файл строк k = 100. Оба потока читают строки из файла и выводят их в правой части экрана в виде: потокid потока текущее время (мсек) строка из файла Варианты индивидуальных заданий 1. Разработать программу по условию п.3, но вместо потоков создать 3 процесса, которые осуществляют те же функции, что и в п.3 (читают строки из файла и выводят их в правой части экрана) в виде: процессpid процесса текущее время (мсек) строка из файла. 2. Написать программу нахождения массива K последовательных значений функции y[i]=sin(2*PI*i/N)(i=0,1,2…K-1) с использованием ряда Тейлора. Пользователь задаёт значения K, N и количество n членов ряда Тейлора. Для расчета каждого члена ряда Тейлора запускается отдельная нить. Каждая нить выводит на экран свой id и рассчитанное значение ряда. Головной процесс суммирует все члены ряда Тейлора, и полученное значение y[i] записывает в файл. 3. Написать программу синхронизации двух каталогов, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2. В результате работы программы файлы, имеющиеся в Dir1, но отсутствующие в Dir2, должны скопироваться в Dir2 вместе с правами доступа. Процедуры копирования должны запускаться с использованием функции fork() в отдельном процессе для каждого копируемого файла. Каждый процесс выводит на экран свой pid, имя копируемого файла и число скопированных байт. Число запущенных процессов не должно превышать N (вводится пользователем). 4. Написать программу поиска одинаковых по их содержимому файлов в двух каталогов, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2. В результате работы программы файлы, имеющиеся в Dir1, сравниваются с файлами в Dir2 по их содержимому. Процедуры сравнения должны запускаться с использованием функции fork() в отдельном процессе для каждой пары сравниваемых файлов. Каждый процесс выводит на экран свой pid, имя файла, число просмотренных байт и результаты сравнения. Число запущенных процессов не должно превышать N (вводится пользователем). 5. Написать программу поиска заданной пользователем комбинации из m байт (m < 255) во всех файлах текущего каталога. Пользователь задаёт имя каталога. Главный процесс открывает каталог и запускает для каждого файла каталога отдельный процесс поиска заданной комбинации из m байт. Каждый процесс выводит на экран свой pid, имя файла, число просмотренных байт и результаты поиска. Число запущенных процессов не должно превышать N (вводится пользователем). 6. Разработать программу «интерпретатор команд», которая воспринимает команды, вводимые с клавиатуры, и осуществляет их корректное выполнение. Для этого каждая вводимая команда должна выполняться в отдельнозапускаемом процессе с использованием вызова exec(). Предусмотреть контроль ошибок. 7. Создать дерево процессов/потоков по индивидуальному заданию. Каждый процесс/поток постоянно, через время t, выводит на экран следующую информацию: номер процесса/потока pidppid текущее время (мсек). Время t =((номер процесса/потока по дереву)*200 (мсек).
Лабораторная работа №5
|
||
|
Последнее изменение этой страницы: 2016-08-16; просмотров: 2332; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.21 (0.009 с.) |