Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Процессы и потоки в ОС Windows

Поиск

Цель работы: изучить методы создания процессов и потоков в ОС Windows, основные функции управления процессами и потоками, обмен данными между процессами и потоками.

Теоретическая часть

 

Для создания процесса в Windows используется функция

BOOL CreateProcess(

LPCTSTR lpApplicationName, // имя исполняемого модуля

LPTSTR lpCommandLine, // Командная строка

LPSECURITY_ATTRIBUTES lpProcessAttributes, //Указатель на структуру

LPSECURITY_ATTRIBUTES lpThreadAttributes, //Указатель на структуру

BOOL bInheritHandles, //Флаг наследования текущего процесса

DWORD dwCreationFlags, //Флаги способов создания процесса

LPVOID lpEnvironment, //Указатель на блок среды

LPCTSTR lpCurrentDirectory, //Текущий диск или каталог

LPSTARTUPINFO lpStartupInfo, //Указатель на структуру STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation //Указатель на структуру

);

Основным параметром является имя исполняемого модуля, соответствующее имени программы, запускаемой во вновь созданном процессе. Пример:

Void main()

{

STARTUPINFO si;

ZeroMemory(&si,sizeof(STARTUPINFO));

PROCESS_INFORMATION pi;

CreateProcess("c:\\1.exe",null,null,null,false,null,null,nulL,&si,&pi)

Для создания потока (нити) в Windows используется функция:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты защиты

DWORD dwStackSize, //размер стека

LPTHREAD_START_ROUTINE lpStartAddress, //адрес функции потока

LPVOID lpParameter, //параметр, который будет передан функции потока

DWORD dwCreationFlags, // 0 - исполнение начинается немедленно

LPDWORD lpThreadId // идентификатор id нового потока

);

При каждом вызове этой функции система создает объект ядра (поток) и выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.

Для передачи сообщений используется специальная win32 -функция:

LRESULT SendMessage(HWND hWnd, //handle окна

UINT Msg, // посылаемое сообщение

WPARAM wParam, // первый параметр сообщения

LPARAM lParam // второй параметр сообщения

);

Выяснив Window handle нужного окна, вы можете посылать ему Windows Messages.

 

Порядок выполнения работ

 

1. Написать программу, запускающую в новом процессе программу notepad.

2. Написать программу, запускающую новый поток в текущем процессе. В потоке выполняется функция выводящая каждые 50 мс на экран следующее сообщение: номер_сообщения id_потока текущее_время (сек:мсек).

3. Написать программу А, запускающую в новом процессе программу B. Обе программы должны посылать друг другу сообщения Windows message.

 

Варианты индивидуальных заданий

1. Создать дерево процессов/потоков по индивидуальному заданию. Каждый процесс/поток постоянно, через время t, выводит на экран следующую информацию:

номер процесса/потока pidтекущее время (мсек).

Время t =((номер процесса/потока по дереву)*200 (мсек).

2. Написать программу, выводящую на экран список запущенных процессов и потоков и их атрибуты (pid и др.) в виде таблицы.

3. Написать программу нахождения массива K последовательных значений функции y[i]=sin(2*PI*i/N) (i=0,1,2…K-1) с использованием ряда Тейлора. Пользователь задаёт значения K, N и количество n членов ряда Тейлора. Для расчета каждого члена ряда Тейлора запускается отдельный поток. Каждый поток выводит на экран свой pid и рассчитанное значение ряда. Головной процесс суммирует все члены ряда Тейлора и полученное значение y записывает в массив и в файл пользователя.

4. Написать программу синхронизации двух каталогов, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2. В результате работы программы файлы, имеющиеся в Dir1, но отсутствующие в Dir2, должны скопироваться в Dir2. Процедуры копирования должны запускаться в отдельном потоке для каждого копируемого файла. Число запущенных потоков не должно превышать N (вводится пользователем). Каждый поток выводит на экран свой id, имя копируемого файла и число скопированных байт.

5. Написать программу поиска одинаковых по их содержимому файлов в двух каталогов, например, Dir1 и Dir2. Пользователь задаёт имена Dir1 и Dir2. В результате работы программы файлы, имеющиеся в Dir1, сравниваются с файлами в Dir2 по их содержимому. Процедуры сравнения должны запускаться в отдельном потоке для каждой пары сравниваемых файлов. Каждый потоке выводит на экран свой id, имя файла, число просмотренных байт и результаты сравнения. Число запущенных потоков не должно превышать N (вводится пользователем).

6. Написать программу поиска заданной пользователем комбинации из m байт (m < 255) во всех файлах текущего каталога. Пользователь задаёт имя каталога. Главный процесс открывает каталог и запускает для каждого файла каталога отдельный поток поиска заданной комбинации из m байт. Каждый поток выводит на экран свой id, имя файла, число просмотренных байт и результаты поиска. Число запущенных потоков не должно превышать N (вводится пользователем).

 

Лабораторная работа №6

СРЕДСТВА МЕЖПРОЦЕССНОГО ВЗАИМОДЕЙСТВИЯ ОС

Цель работы – изучить методы и средства взаимодействия процессов в ОС Linux.

Теоретическая часть

Все процессы в Linux выполняются в раздельных адресных пространствах и для организации межпроцессного взаимодействия необходимо использовать специальные методы:

1. общие файлы;

2. общую или разделяемую память;

3. очереди сообщений (queue);

4. сигналы (signal);

5. каналы (pipe);

6. семафоры.

1. При использовании общих файлов оба процесса открывают один и тот же файл, с помощью которого и обмениваются информацией. Для ускорения работы следует использовать файлы, отображаемые в памяти при помощи системного вызова mmap():

#include <unistd.h>
#include <sys/mman.h>

void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

Функция mmap отображает length байтов, начиная со смещения offset файла, определенного файловым описателем fd, в память, начиная с адреса start. Последний параметр offset необязателен, и обычно равен 0. Настоящее местоположение отраженных данных возвращается самой функцией mmap, и никогда не бывает равным 0. Аргумент prot описывает желаемый режим защиты памяти (он не должен конфликтовать с режимом открытия файла):

PROT_EXEC данные в памяти могут исполняться;

PROT_READ данные в памяти можно читать;

PROT_WRITE в область можно записывать информацию;

PROT_NONE доступ к этой области памяти запрещен.

Параметр flags задает тип отражаемого объекта, опции отражения и указывает, принадлежат ли отраженные данные только этому процессу или их могут читать другие. Он состоит из комбинации следующих битов:

MAP_FIXED использование этой опции не рекомендуется;

MAP_SHARED разделить использование этого отражения с другими процессами, отражающими тот же объект. Запись информации в эту область памяти будет эквивалентна записи в файл. Файл может не обновляться до вызова функций msync(2) или munmap(2);

MAP_PRIVATE создать неразделяемое отражение с механизмом copy-on-write. Запись в эту область памяти не влияет на файл. Не определено, являются или нет изменения в файле после вызова mmap видимыми в отраженном диапазоне.

2. Использование разделяемой памяти заключается в создании специальной области памяти, позволяющей иметь к ней доступ нескольким процессам. Системные вызовы для работы с разделяемой памятью:

#include <sys/mman.h>

int shm_open (const char *name, int oflag, mode_t mode);

int shm_unlink (const char *name);

Вызов shm_open создает и открывает новый (или уже существующий) объект разделяемой памяти. При открытии с помощью функции shm_open() возвращается файловый дескриптор. Имя name трактуется стандартным для рассматриваемых средств межпроцессного взаимодействия образом. Посредством аргумента oflag могут указываться флаги O_RDONLY, O_RDWR, O_CREAT, O_EXCL и/или O_TRUNC. Если объект создается, то режим доступа к нему формируется в соответствии со значением mode и маской создания файлов процесса. Функция shm_unlink выполняет обратную операцию, удаляя объект, предварительно созданный с помощью shm_open. После подключения сегмента разделяемой памяти к виртуальной памяти процесса этот процесс может обращаться к соответствующим элементам памяти с использованием обычных машинных команд чтения и записи, не прибегая к использованию дополнительных системных вызовов.

int main (void) {

int fd_shm; /* Дескриптор объекта в разделяемой памяти*/

if ((fd_shm = shm_open (“myshered.shm”, O_RDWR | O_CREAT, 0777)) < 0) { perror ("error create shm"); return (1); }

Для компиляции программы необходимо подключить библиотеку rt.lib следующим способом: gcc 1.c –o 1.exe -lrt

3. Очереди сообщений (queue) являются более сложным методом связи взаимодействующих процессов по сравнению с программными каналами. С помощью очередей также можно из одной или нескольких задач независимым образом посылать сообщения некоторой задаче-приемнику. При этом только процесс-приемник может читать и удалять сообщения из очереди, а процессы-клиенты имеют право лишь помещать в очередь свои сообщения. Очередь работает только в одном направлении, если необходима двухсторонняя связь, следует создать две очереди. Очереди сообщений предоставляют возможность использовать несколько дисциплин обработки сообщений:

· FIFO – сообщение, записанное первым, будет прочитано первым;

· LIFO – сообщение, записанное последним, будет прочитано первым;

· приоритетная – сообщения читаются с учетом их приоритетов;

· произвольный доступ – можно читать любое сообщение, а программный канал обеспечивает только дисциплину FIFO.

Для открытия очереди служит функция mq_open(), которая, по аналогии с файлами, создает описание открытой очереди и ссылающийся на него дескриптор типа mqd_t, возвращаемый в качестве нормального результата.

#include <mqueue.h>

mqd_t mq_open (const char *name, int oflag,...);

При чтении сообщения из очереди оно не удаляется, а может быть прочитано несколько раз. В очередях реально присутствуют не сами сообщения, а только их адреса в памяти и размеры. Эта информация размещается системой в сегменте памяти, доступном для всех задач, общающихся с помощью данной очереди. Каждый процесс, использующий очередь, должен предварительно получить разрешение на использование общего сегмента памяти с помощью системных запросов, потому что очередь – системный механизм и для работы с ней требуются системные ресурсы и обращение к самой ОС.

4. Сигналы. С точки зрения пользователя получение процессом сигнала выглядит как возникновение прерывания. Процесс прерывает исполнение, и управление передается функции-обработчику сигнала. По окончании обработки сигнала процесс может возобновить регулярное исполнение. Типы сигналов принято задавать специальными символьными константами. Системный вызов kill() предназначен для передачи сигнала одному или нескольким специфицированным процессам в рамках полномочий пользователя.

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid, int signal);

Послать сигнал (не имея полномочий суперпользователя) можно только процессу, у которого эффективный идентификатор пользователя совпадает с эффективным идентификатором пользователя для процесса, посылающего сигнал. Аргумент pid указывает процесс, которому посылается сигнал, а аргумент sig – какой сигнал посылается. В зависимости от значения аргументов:

pid > 0 сигнал посылается процессу с идентификатором pid;

pid=0 сигнал посылается всем процессам в группе, к которой принадлежит посылающий процесс;

pid=-1 и посылающий процесс не является процессом суперпользователя, то сигнал посылается всем процессам в системе, для которых идентификатор пользователя совпадает с эффективным идентификатором пользователя процесса, посылающего сигнал.

pid = -1 и посылающий процесс является процессом суперпользователя, то сигнал посылается всем процессам в системе, за исключением системных процессов (обычно всем, кроме процессов с pid = 0 и pid = 1).

pid < 0, но не –1, то сигнал посылается всем процессам из группы, идентификатор которой равен абсолютному значению аргумента pid (если позволяют привилегии).

если sig = 0, то производится проверка на ошибку, а сигнал не посылается. Это можно использовать для проверки правильности аргумента pid (есть ли в системе процесс или группа процессов с соответствующим идентификатором).

Системные вызовы для установки собственного обработчика сигналов:

#include <signal.h>

void (*signal (int sig, void (*handler) (int)))(int);

int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);

Структура sigaction имеет следующий формат:

struct sigaction {

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

Системный вызов signal служит для изменения реакции процесса на какой-либо сигнал. Параметр sig – это номер сигнала, обработку которого предстоит изменить. Параметр handler описывает новый способ обработки сигнала – это может быть указатель на пользовательскую функцию-обработчик сигнала, специальное значение SIG_DFL (восстановить реакцию процесса на сигнал sig по умолчанию) или специальное значение SIG_IGN (игнорировать поступивший сигнал sig). Системный вызов возвращает указатель на старый способ обработки сигнала, значение которого можно использовать для восстановления старого способа в случае необходимости.

Пример пользовательской обработки сигнала SIGUSR1.

void *my_handler(int nsig) { код функции-обработчика сигнала }

int main() {

(void) signal(SIGUSR1, my_handler); }

Системный вызов sigaction используется для изменения действий процесса при получении соответствующего сигнала. Параметр sig задает номер сигнала и может быть равен любому номеру. Если параметр act не равен нулю, то новое действие, связянное с сигналом sig, устанавливается соответственно act. Если oldact не равен нулю, то предыдущее действие записывается в oldact.

5. Каналы. Программный канал – это файл особого типа (FIFO: «первым вошел – первым вышел»). Процессы могут записывать и считывать данные из канала как из обычного файла. Если канал заполнен, процесс записи в канал останавливается до тех пор, пока не появится свободное место, чтобы снова заполнить его данными. С другой стороны, если канал пуст, то читающий процесс останавливается до тех пор, пока пишущий процесс не запишет данные в этот канал. В отличие от обычного файла здесь нет возможности позиционирования по файлу с использованием указателя.

В ОС Linux различают два вида программных каналов:

· Именованный программный канал. Именованный программный канал может служить для общения и синхронизации произвольных процессов, знающих имя данного программного канала и имеющих соответствующие права доступа. Для создания используется вызов:

int mkfifo(const char *filename, mode_t mode);

· Неименованный программный канал. Неименованным программным каналом могут пользоваться только создавший его процесс и его потомки. Для создания используется вызов:

int pipe(int fd[2]);

6. Семафор – переменная определенного типа, которая доступна параллельным процессам для проведения над ней только двух операций:

· A(S, n) – увеличить значение семафора S на величину n;

· D(S, n) – если значение семафора S < n, процесс блокируется. Далее S = S - n;

· Z(S) – процесс блокируется до тех пор, пока значение семафора S не станет равным 0.

Семафор играет роль вспомогательного критического ресурса, так как операции A и D неделимы при своем выполнении и взаимно исключают друг друга. Семафорный механизм работает по схеме, в которой сначала исследуется состояние критического ресурса, а затем уже осуществляется допуск к критическому ресурсу или отказ от него на некоторое время. Основным достоинством семафорных операций является отсутствие состояния «активного ожидания», что может существенно повысить эффективность работы мультипрограммной вычислительной системы.

Для работы с семафорами имеются следующие системные вызовы:

Создание и получение доступа к набору семафоров:

int semget(key_t key, int nsems, int semflg);

Параметр ke y является ключом для массива семафоров, т.е. фактически его именем. В качестве значения этого параметра может использоваться значение ключа, полученное с помощью функции ftok(), или специальное значение IPC_PRIVATE. Использование значения IPC_PRIVATE всегда приводит к попытке создания нового массива семафоров с ключом, который не совпадает со значением ключа ни одного из уже существующих массивов и не может быть получен с помощью функции ftok() ни при одной комбинации ее параметров. Параметр nsems определяет количество семафоров в создаваемом или уже существующем массиве. В случае если массив с указанным ключом уже имеется, но его размер не совпадает с указанным в параметре nsems, констатируется возникновение ошибки.

Параметр semflg – флаги – играет роль только при создании нового массива семафоров и определяет права различных пользователей при доступе к массиву, а также необходимость создания нового массива и поведение системного вызова при попытке создания. Он является некоторой комбинацией (с помощью операции побитовое или – " | ") следующих предопределенных значений и восьмеричных прав доступа:

IPC_CREAT — если массива для указанного ключа не существует, он должен быть создан;

IPC_EXCL — применяется совместно с флагом IPC_CREAT. При совместном их использовании и существовании массива с указанным ключом, доступ к массиву не производится и констатируется ошибка, при этом переменная errno, описанная в файле < errno.h >, примет значение EEXIST;

0400 — разрешено чтение для пользователя, создавшего массив

0200 — разрешена запись для пользователя, создавшего массив

0040 — разрешено чтение для группы пользователя, создавшего массив

0020 — разрешена запись для группы пользователя, создавшего массив

0004 — разрешено чтение для всех остальных пользователей

0002 — разрешена запись для всех остальных пользователей

Пример: semflg= IPC_CREAT | 0022

Изменение значений семафоров:

int semop(int semid, struct sembuf *sops, int nsops);

Параметр semid является дескриптором System V IPC для набора семафоров, т. е. значением, которое вернул системный вызов semget() при создании набора семафоров или при его поиске по ключу. Каждый из nsops элементов массива, на который указывает параметр sops, определяет операцию, которая должна быть совершена над каким-либо семафором из массива IPC семафоров, и имеет тип структуры:

struct sembuf {

short sem_num; //номер семафора в массиве IPC семафоров (начиная с 0);

short sem_op; //выполняемая операция;

short sem_flg; // флаги для выполнения операции.

}

Значение элемента структуры sem_op определяется следующим образом:

· для выполнения операции A(S,n) значение должно быть равно n;

· для выполнения операции D(S,n) значение должно быть равно - n;

· для выполнения операции Z(S) значение должно быть равно 0.

Семантика системного вызова подразумевает, что все операции будут в реальности выполнены над семафорами только перед успешным возвращением из системного вызова. Если при выполнении операций D или Z процесс перешел в состояние ожидания, то он может быть выведен из этого состояния при возникновении следующих форсмажорных ситуаций: массив семафоров был удален из системы; процесс получил сигнал, который должен быть обработан.

Выполнение разнообразных управляющих операций (включая удаление) над набором семафоров:

int semctl(int semid, int semnum, int cmd, union semun arg);

Изначально все семафоры инициируются нулевым значением.

 

Порядок выполнения работы

1. Изучить теоретическую часть лабораторной работы

2. Написать программу, создающую дочерний процесс. Родительский процесс создаёт семафор (сем1) и общий файл. Дочерний процесс записывает в файл по одной строке всего 100 строк вида: номер_строкиpid_процессатекущее_время (мсек). Родительский процесс читает из файла строки и выводит их на экран в следующем виде: pid строка_прочитанная_из_файла. Семафор сем1 используется процессами для разрешения, кому из процессов получить доступ к файлу.

3. Написать программу, создающую дочерний процесс. Родительский процесс создаёт неименованный канал. Дочерний процесс записывает в канал 100 строк вида: номер_строкиpid_процессатекущее_время (мсек). Родительский процесс читает из канала строки и выводит их на экран в следующем виде: pid строка прочитанная из файла.

Варианты индивидуальных заданий

 

1. Cоздать два дочерних процесса. Родительский процесс создаёт семафор (сем1) и общий файл отображенный в память. Оба дочерних процесса непрерывно записывают в файл по 100 строк вида: номер_строкиpid_процессатекущее_время (мсек). Всего процессы должны записать 1000 строк. Семафор сем1 используется процессами для разрешения кому из процессов получить доступ к файлу. Родительский процесс читает из файла по 75 строк и выводит их на экран. Дочерние процессы начинают операции с файлом после получения сигнала SIGUSR1 отродительского процесса.

2. Cоздать два дочерних процесса. Родительский процесс создаёт семафоры (сем1), (сем2) и 2 неименованных канала (кан1 и кан2). Оба дочерних процесса непрерывно записывают в каналы по 100 строк вида: номер_строкиpid_процессатекущее_время (мсек). Всего процессы должны записать 1000 строк. Семафоры (сем1), (сем2) используются процессами для разрешения кому из процессов получить доступ к каналу. Родительский процесс читает из каждого канала по 75 строк и выводит их на экран. Дочерние процессы начинают операции с каналами после получения сигнала SIGUSR2 отродительского процесса.

3. Cоздать два дочерних процесса. Родительский процесс создаёт семафор (сем1) и разделяемую память. Оба дочерних процесса непрерывно записывают в разделяемую память по 100 строк вида: номер_строкиpid_процессатекущее_время (мсек). Всего процессы должны записать 1000 строк. Семафор сем1 используется процессами для разрешения кому из процессов получить доступ к разделяемой памяти. Родительский процесс читает из разделяемой памяти по 75 строк и выводит их на экран. Дочерние процессы начинают операции с файлом после получения сигнала SIGUSR1 отродительского процесса.

ЛИТЕРАТУРА

 

ОСНОВНАЯ

 

1. Таненбаум, Э. Современные операционные системы/ Э. Таненбаум.– 2-е изд. – СПб.: Питер, 2002. – 1040 с.

2. Столингс В. Операционные системы/ В. Столингс – 3-е изд. – М.: Вильямс, 2002. – 848 с.

3. Руссинович, М. Внутреннее устройство Microsoft Windows: Windows Server 2003, Windows XP и Windows 2000 / М. Руссинович, Д. Соломон. пер. с англ. – 4-е издание – М.: Русская Редакция; СПб.: Питер, 2005. – 992 c.

4. Олифер, В.Г., Олифер, Н.А.. Сетевые операционные системы. Учебник. – СПб.: Питер, 2001. – 544 с.

 

Дополнительная

 

5. Робачевский, А.М. Операционная система Unix/ А.М. Робачевский. – Спб.: BHV – Санкт-Петербург, 1997. – 528 с.

6. Нортон, П. Руководство П.Нортона: MS Windows 2000 Professional/ П. Нортон – М.: Русская Редакция, 2001. – 480 с.

7. Буза, М. К. Операционная среда Windows и ее приложения/ М. К. Буза. – Мн.: Выш. ш., 1997. – 341 с.

8. Валединский В.Д. Информатика. Словарь компьютерных терминов/ В.Д. Валединский. – М.: Аквариум, 1997. – 226 с.

9. Гордеев, А. В. Системное программное обеспечение/ А. В. Гордеев, А. Ю. Молчанов.– СПб.: Питер, 2003. – 736 с.

 



Поделиться:


Последнее изменение этой страницы: 2016-08-16; просмотров: 1272; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.105.85 (0.01 с.)