254.90K
Категория: ПрограммированиеПрограммирование

Механизмы управления программами

1.

Механизмы управления
программами
1

2.

Структура раздела
• Процессы




Понятие процесса
Управление процессами
Процессы и потоки
Параллельные процессы
• Процессы в ОС UNIX




Атрибуты процессов
Состояния процесса
Создание и уничтожение процессов
Организация взаимодействия процессов
• Процессы в ОС Windows
– Особенности процессов
– Взаимодействие процессов
2

3.

Процессы
3

4.

Понятие процесса
• Процесс – некоторая деятельность,
связанная с исполнением программы на
процессоре.
• Процесс – система действий, реализующая
определенную функцию в вычислительной
системе и оформленная так, что
управляющая программа вычислительной
системы может перераспределять ресурсы
этой системы в целях обеспечения
мультипрограммирования. [ГОСТ 19781-83]
4

5.

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

6.

• По динамическому признаку
Последовательные процессы – процессы, которые не могут
выполняться одновременно.
Параллельные процессы – одновременно выполняющиеся
процессы.
Комбинированные – если в процессах имеются точки, в которых
существует один из параллельных процессов и не существует
другой.
• По связности
Изолированные процессы – полностью независимые процессы.
Информационно-независимые процессы – используют общие
ресурсы, но не связаны по информации.
Взаимодействующие процессы – процессы имеют
информационные связи.
Конкурирующие – процессы взаимосвязаны по информации и
используют общие ресурсы.
6

7.

Состояния процесса
Порождение
Готовность
Активное
Ожидание
Окончание
7

8.

Атрибуты процессов
• Идентификатор процесса
• Таблицы адресов выделенных
процессу областей памяти
• Таблицы файлов
• Приоритет процесса
• Состояние процесса
• Информация о связанных с процессом
событиях
• Контекст процесса
8

9.

Управление процессами
• Основные функции ОС
Создание и удаление процессов
Планирование и диспетчеризация
Синхронизация процессов и обеспечение их
средствами взаимодействия
9

10.

Планирование
• Планирование – управление
очередями с целью минимизации
задержек и максимизации
производительности системы
• Виды планирования
Долгосрочное планирование
Среднесрочное планирование
Краткосрочное планирование
(диспетчеризация)
10

11.

Уровни планирования
Краткосрочно
Краткосрочное
е
планирование
планировани
Выполнение
Готов
Блокирован
Среднесрочное
планирование
Долгосрочное
планирование
Блокирован
приостановлен
Готов
приостановлен
Создание
Завершение
11

12.

Приоритет зависит
от времени
обслуживания
Приоритет зависит
от времени
ожидания
Динамические
приоритеты
Фиксированны
е приоритеты
Нелинейные
Линейные
Бесприоритетные
Адаптивное
обслуживание
С абсолютным
приоритетом
С относительным
приоритетом
Многоприоритетный
циклический
Циклический
алгоритм
Случайный выбор
В порядке очереди
Дисциплины диспетчеризации
Приоритетные
12

13.

В порядке очереди (FIFO)
Процессор
Очередь
13

14.

Циклический алгоритм (Round robin)
Порядок просмотра
очередей
Очереди
Процессор
Обслуженные
заявки
Заявки, обслуживание
которых не закончено
14

15.

Процессы и потоки
• Многопоточность - способность ОС
поддерживать в рамках одного
процесса выполнение нескольких
потоков.
• Поток имеет состояния, контекст, стек,
локальную память.
• Поток выполняется в адресном
пространстве процесса.
15

16.

Один поток
Несколько потоков
16

17.

Поток 1
Блок управления
процессом
Адресное
пространство
Поток 2
Управляющий блок
потока
Управляющий блок
потока
Стек пользователя
Стек пользователя
Стек ядра
Стек ядра
Процесс
17

18.

Параллельные процессы
• Взаимодействующие процессы имеют
информационные связи и используют
общие ресурсы
• Критический ресурс не допускает
одновременное использование
несколькими процессами
18

19.

Конкурирующие процессы
Процесс 2
Процесс 1
Запрос
Критический ресурс
Критическая
секция
Запрос
Блокировка
Освобождение
Освобождение
19

20.

Блокирующие переменные
Проверка
занятости
нет
F==1
Занять ресурс
да
F=0
F – блокирующая
переменная
Критическая
секция
Освободить
ресурс
F=1
20

21.

Семафоры Дейкстры
• S – семафор
• P(S) – операция закрытия (проверки)
• V(S) – операция открытия (увеличения)
P(S): if S>0 then S:=S-1;
else WAIT(S) {перевести процесс в
очередь ожидания к семафору S}
V(S): if есть процессы, ожидающие семафор S
then
RELEASE(S) {перевести один из процессов
очереди S в очередь готовности}
else
S:=S+1;
21

22.

Взаимное исключение
var S: semafore;
begin
S:=1;
parbegin
ПР1:
begin
P(S);
{критическая секция}
V(S);
end
ПР2:
begin
P(S);
{критическая секция}
V(S);
end
parend
end
22

23.

Производитель - потребитель
Производитель
Ресурс
Потребитель
Читатели - писатели
Писатели
Ресурс
Читатели
23

24.

var S_св, S_зап , S_иск;
begin
S_св:=1;
S_зап:=0;
S_иск:=1;
parbegin
ПРОИЗВОДИТЕЛЬ:
while true do
begin
{подготовка сообщения}
P(S_св);
P(S_иск);
{запись сообщения}
V(S_зап);
V(S_иск);
end
and
24

25.

ПОТРЕБИТЕЛЬ:
while true do
begin
P(S_зап);
P(S_иск);
{прием сообщения}
V(S_св);
V(S_иск);
{обработка сообщения}
end
parend
end
25

26.

"Читатели – писатели" с приоритетом читателей
var R,W: semaphore;
NR: integer;
procedure ЧИТАТЕЛЬ;
begin
P(R);
NR:=NR+1;
if NR = 1 then P(W);
V(R);
Read_Data; {критический интервал}
P(R);
NR:=NR-1;
if NR = 0 then V(W);
end;
26

27.

procedure ПИСАТЕЛЬ;
begin
P(W);
Write_Data;
V(W);
end
begin
NR:=0;
InitSem(R,1); InitSem(W,1);
parbegin
while true do ЧИТАТЕЛЬ
and
while true do ЧИТАТЕЛЬ
and
………………….
27

28.

while true do ЧИТАТЕЛЬ
and
while true do ПИСАТЕЛЬ
and
while true do ПИСАТЕЛЬ
and
………………….
while true do ПИСАТЕЛЬ
parend
end.
28

29.

Счетные семафоры (Читатели-писатели)
var S: sevmafore;
Q,R: integer;
begin R:=1; Q:=n; {Инициализация}
parbegin
ЧИТАТЕЛЬ: do
{……….}
P(S,R);
{Чтение}
V(S,R);
end;
29

30.

ПИСАТЕЛЬ: do
{…………..}
P(S,Q);
{запись}
V(S,Q);
end;
parend
end
30

31.

Обедающие философы
31

32.

Множественные семафоры
var S: array 1..5 of semaphore;
i: integer;
begin
i:=5;
repeat S[i]:=1; i:=i-1; until i=0;
parbegin
1: begin {тело процесса}
…………………………
32

33.

i: begin
var left, right: 1..5;
begin
left:=(i-1) mod 5;
right:= (i+1) mod 5;
repeat
{размышления}
P(S[left]; S[right]);
{критическая секция}
V(S[left]; S[right]);
end repeat;
end
end
parend
end
33

34.

Тупики
• Взаимные блокировки (deadlock)
П1
П2
Р1
Р2
34

35.

Условия возникновения
1.
2.
3.
4.
Взаимные исключения. Одновременно
использовать ресурсы может только один процесс.
Удержание и ожидание. Процесс может
удерживать ресурсы во время ожидания.
Отсутствие перераспределения. Ресурс не может
быть отобран у удерживающего его процесса.
Циклическое ожидание. Существует замкнутая
цепь процессов, каждый из которых удерживает
минимум один ресурс, необходимый процессу,
следующему в цепи после данного.
35

36.

Предотвращение тупиков
1. Условие взаимного исключения можно
подавить путем неограниченного
разделения ресурсов.
2. Условие ожидания предотвращается, если
выделять все необходимые ресурсы при
создании процесса.
3. Условие отсутствия перераспределения
можно исключить, позволяя ОС отбирать
ресурсы у процесса.
4. Условие кругового ожидания можно
исключить избегая образования цепи
запросов.
36

37.

Процессы в ОС UNIX
37

38.

Виды процессов
Системные процессы.
Системные процессы – часть ядра. Запускаются при
инициализации системы.
- управление свопингом.
- буферизация.
- управление памятью и т. д.
особую роль играет системный процесс init – прародитель
(инициатор) всех остальных процессов.
Демоны
Специальные процессы, запускаемые при инициализации
системы в фоновом режиме. Не имеет связи с пользователями.
- управление системой печати.
- сетевой сервис.
- терминальный доступ и т. д.
Прикладные процессы
Основные процессы системы. Обычно прикладные процессы
порождаются сеансами пользователей. Широкий цикл
прикладных процессов ограничен сеансом работы
пользователя.
38

39.

Атрибуты процесса
Идентификатор процесса (PID)
Идентификатор родительского процесса (PPID)
Реальный идентификатор пользователя (RID)
Эффективный идентификатор пользователя (EUID)
Реальный идентификатор группы (RGID )
Эффективный идентификатор группы (EGID)
Идентификатор группы процесса (PGID)
Идентификатор сеанса (SID)
Приоритет процесса (Nice Number)
Текущий каталог
Корневой каталог
39

40.

Дескриптор процесса
Таблица
процессов
PID
PCB
Блок управления
процессом (PCB)
Программный счетчик
Регистры
Состояние
1
Приоритет
2
Адресное пространство
...
n
Родительский процесс
Дочерние процессы
Открытые файлы
.................
Другие флаги
40

41.

Состояния процесса
41

42.

Создание и уничтожение процессов
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
42

43.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
int pid;
pid = fork();
if (pid == -1){
perror("fork");
exit (1);}
if (pid == 0)
printf("Дочерний PID=%d \n", pid);
else
printf("Родительский PID=%d \n", pid);
return 0;
}
43

44.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int x, pid;
x=2;
printf("Один процесс, x=%d\n",x);
pid=fork();
if(pid == 0)
printf("Дочерний процесс, x=%d\n",x);
else if(pid > 0){
printf("Родительский процесс, pid=%d, x=%d\n",pid,x);
sleep(5);
wait(pid);
}
else {
perror("Ошибка fork()");
return -1;
}
return EXIT_SUCCESS;
}
44

45.

Результат выполнения fork()
• Отводится место в таблице процессов под
новый процесс
• Порожденному процессу присваивается
идентификатор
• Создается логическая копия родительского
процесса
• Увеличиваются значения счетчика числа
файлов, связанных с процессом
• Идентификатор порожденного процесса
возвращается родительскому процессу
45

46.

Порожденный процесс наследует
Идентификаторы пользователя и группы
Переменные окружения
Сигналы и их обработчики
Ограничения, накладываемые на процесс
Текущий и корневой каталоги
Маску создания файлов
Файловые дескрипторы и указатели
Управляющий терминал
46

47.

Различия между процессами
• Порожденный процесс имеет свой
идентификатор PID
• Идентификаторы родительского процесса
PPID различны
• Порожденный процесс не наследует
сигналов, ожидающих доставки
• Значения, возвращаемые вызовом fork()
различно для родителя и потомка
47

48.

Завершение процесса
• Процесс завершается по функции exit. Код
нормального завершения 0.
• Действия:




Отключаются сигналы.
Сохраняется код возврата и статистика выполнения.
Процесс переходит в состояние "зомби".
Освобождается адресное пространство процесса и области
свопинга.
– Родительскому процессу отправляется сигнал SIGCHILD.
– Пробуждается ожидающий завершения потомка
родительский процесс.
– Запускается функция переключения контекста.
48

49.

Синхронизация процессов
#include <sys/wait.h>
pid_t wait(int* status_p);
pid_t waitpid(pid_t child_pid, int* status, int option);
WNOHANG – неблокирующий вызов (если нет порожденного
процесса функция немедленно возвратит управление)
WUNTRACED – ожидание остановленного процесса
49

50.

Запуск новой программы
Дерево семейства вызовов exec
execl
execle
execv
execlp
execvp
execve
50

51.

Аргументы передаются списком
execl(const char* path, const char *arg0,…,const char *argn, NULL);
передается полный путь к программе
execlp(const char* file, const char *arg0,…,const char *argn, NULL);
передается только имя файла
execle(const char* path, const char *arg0,…, const char** env);
дополнительно передается указатель на массив переменных окружения
Передается массив аргументов
execv(const char* path, const char *argv[ ]);
передается полный путь к программе
execvp(const char* file, const char *argv[ ]);
передается только имя файла
execve(const char* path, const char ** argv,…,const char** env);
дополнительно передается указатель на массив переменных окружения
51

52.

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
int main()
{ pid_t pid;
int status;
if ((pid=fork())==-1) {
perror("Error fork");
return -1;
}
52

53.

if (pid == 0) {
printf("Child\n");
execl("/home/sbd/child",NULL);
perror("execl");
exit(errno);
}
else {
printf("Parent\n");
wait(&status);
exit (0);
}
}
53

54.

Вызываемая программа
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
sleep(4);
printf("Execut child\n");
exit (0);
}
54

55.

Планирование процессов
Таймер
Фиксированный тик – интервал между соседними
прерываниями.
Функции обработчика прерываний от таймера:
•Обновление статистики использования процессом ЦП
•Пересчет приоритетов и проверка истечения кванта
•Обновление системного времени и таймеров
•Пробуждение системных процессов
•Обработка отложенных вызовов
•Обработка сигналов alarm
55

56.

Функции работы со временем
time.h – ANSI C
time_t time(time_t *tmv); возвращает
количество секунд, прошедшее с 1.01.1970.
Если параметр не NULL, то результат
записывается по заданному указателю.
const char* ctime(const time_t *tmv);
56

57.

struct tm {
int tm_sec;
//секунды
int tm_min;
//минуты
int tm_hour;
//часы (от 0 до 24)
int tm_mday;
//дни месяца (от 1 до 31)
int tm_mon;
//месяц (от 0 до 11)
int tm_year;
// год (после 1900)
int tm_wday;
// день недели (Воскресенье = 0)
int tm_yday;
// день года (от 0 до 365)
int tm_isdst;
//флаг летнего времени (для США)
};
57

58.

struct tm* localtime(const time_t *tmv);
struct tm* gmtime(const time_t *tmv);
time_t mktime(struct tm* tm_ptr);
#include <times.h>
58

59.

#include <iostream.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/times.h>
int main()
{
time_t tick= CLOCKS_PER_SEC;
time_t tmv;
struct tm *tp;
clock_t ctm,etm;
struct tms systime;
ctm = clock();
cout << "Sys time-> "<<ctm << endl;
time(&tmv);
cout << "Local time=" << ctime(&tmv) << endl;
tp=localtime(&tmv);
cout<<1900+tp->tm_year<<','<<tp->tm_mon+1<<endl;
sleep(2);
times(&systime);
cout<<"Task time->"<<systime.tms_utime<<endl;
cout<<"Nuclear time->"<<systime.tms_stime<<endl;
etm = clock()-ctm;
cout<< "Run time="<<etm<<endl;
return EXIT_SUCCESS;
}
59

60.

Алармы
• Таймер реального времени (SIGALARM) используется для подсчета реального
времени
• Таймер профилирования (SIGPROF) –
изменяется , когда процесс находится в
состоянии ядра
• Виртуальный таймер (SIGVTALARM) –
изменяется, когда процесс находится в
состоянии задачи
60

61.

Операции над процессами
Создание процесса
Уничтожение процесса
Приостановка процесса
Возобновление процесса
Изменение приоритета процесса
Блокирование процесса
Пробуждение процесса
Запуск (выбор) процесса
Обеспечение взаимодействия процессов
61

62.

Взаимодействие процессов (IPC)
Сигналы
Каналы (pipe)
Именованные каналы (FIFO)
Сообщения (messages)
Семафоры
Разделяемая память
Сокеты (socket)
62

63.

Сигналы
• Генерация сигнала
Особые ситуации
Терминальные прерывания (Del, Ctrl+C…)
Другие процессы (вызов kill)
Управление заданиями
Квоты
Уведомления
Алармы
63

64.

Доставка и обработка сигнала
• Ядро от имени процесса проверяет наличие
сигнала
• Если сигнал есть, ядро обрабатывает его по
умолчанию, либо запускает специальную
функцию, которая вызывает специальную
функцию обработки сигнала.
kill [сигнал] pid1, pid2,…
kill –l вывод списка идентификаторов сигналов
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig_num);
64

65.

#include <iostream.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
// Handler
void my_hand()
{cout << "Handler\n";}
int main()
{
struct sigaction act, old_act;
cout << "Server" << endl;
act.sa_handler = my_hand;
if (sigaction(SIGUSR1, &act, &old_act) == -1)
perror("Sigaction\n");
pause(); //
return 0;
}
65

66.

// Формирование сигнала
#include <iostream.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
int pid;
cout << "Input PID: ";
cin >> pid;
cout << "Send signal\n" << endl;
kill(pid, SIGUSR1);
return 0;
}
66

67.

Неименованные каналы (pipe)
#include <unistd.h>
Int pipe(int fd[2]);
процесс
процесс
ядро
fd[0]
fd[1]
канал
67

68.

Родительский процесс
Дочерний процесс
fork
fd[0]
fd[0]
fd[1]
fd[1]
Канал
Канал после вызова fork()
68

69.

Родительский процесс
Дочерний процесс
fork
fd[0]
fd[0]
fd[1]
fd[1]
Канал
Односторонний канал
69

70.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
int main()
{
pid_t childPid;
int flds[2], status;
char buf[]="Message";
if (pipe(flds) == -1) {
perror("Pipe");
exit(1);
}
switch (childPid=fork()) {
case -1: perror("fork");
exit(2);
case 0: close(flds[0]);
printf("Child process %d\n", getpid());
write(flds[1], buf, strlen(buf));
close(flds[1]);
exit(0);
}
close(flds[1]);
read(flds[0], buf, 80);
printf("String -> %s\n", buf);
close(flds[0]);
wait(&status);
return status;
}
70

71.

who | sort | lp
who
lp
sort
stdout
stdout
stdin
stdin
Канал 1
Канал 2
71

72.

Двусторонняя передача по двум каналам
родительский процесс
fd2[0]
дочерний процесс
fd1[0]
fd1[1]
fd2[1]
Канал 1
Канал 2
72

73.

Именованные каналы
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
При успешном звершении возвращается 0, в случае ошибки
возвращается -1.
• S_IRUSR – чтение для владельца
• S_IWUSR – запись для владельца
• S_IRGRP – чтение для членов группы
• S_IWGRP – запись для членов группы
• S_IROTH – чтение для прочих пользователей
• S_IWOTH – запись для прочих пользователей
73

74.

Логика открытия объекта IPC
Аргумент oflag
Объект не
существует
Объект уже
существует
OK, открывается
существующий
объект
Нет флагов
Ошибка,
errno = ENOENT
O_CREAT
OK, открывается
OK, создается новый
существующий
объект
объект
O_CREAT | O_EXCL
OK, создается новый
errno = EEXIST
объект
74

75.

#include <iostream.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define NAME " fifo_s.cc"
int main()
{
int fd;
char buf[80];
if(mkfifo(NAME, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO)) {
perror("Ошибка FIFO"); return 1;
}
if((fd=open(NAME, O_RDONLY))==-1) {
perror("Ошибка открытия файла"); return 2;
}
read(fd, buf, sizeof(buf));
cout<<"Получено->"<<buf<<endl;
close(fd);
return 0;
}
75

76.

#include <iostream.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#define NAME " fifo_s.cc"
int main()
{
char text[80];
int fd;
cout<<"Ввести текст-"<<endl;
cin>>text;
if((fd=open(NAME, O_RDWR))==-1) {
perror("Ошибка открытия файла");
return 1;
}
write(fd, text, strlen(text));
close(fd);
return 0;
}
76

77.

Создание ключей
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int id);
Возвращает ключ, в случае ошибки возвращает -1.
Если нужен один канал,
то
id = 1,
иначе
идентификаторы должны быть разными (1 и 2)
77

78.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main()
{
key_t key;
if((key = ftok("main.c",0))==-1)
printf("Error 1\n");
printf("key1->%x\n",key);
if((key = ftok("main.c",0))==-1)
printf("Error 2\n");
printf("key2->%x\n",key);
if((key = ftok("Makefile",0))==-1)
printf("Error 3\n");
printf("key3->%x\n",key);
return EXIT_SUCCESS;
}
key1->77b7d
key2->77b7d
key3->77b80
78

79.

Управляющая структура IPC
struct ipc_perm {
uid_t uid;
//идентификатор пользователя владельца
gid_t gid;
//идентификатор группы владельца
uid_t cuid;
//идентификатор пользователя создателя
gid_t cgid;
//идентификатор группы создателя
mode_t mode; //разрешение чтения-записи
ulong_t seq;
//последовательный номер канала
key_t key;
//ключ IPC
};
Идентификатор создателя изменяться не может
Идентификатор владельца может изменяться функцией управления
79

80.

Сообщения (messages)
Процесс Б
Процесс А
В-Б
А-В
А-Г
Ядро
Процесс Г
А-В
Процесс В
А-Г
В-Б
80

81.

Очереди сообщений
Таблица
сообщений
Область
памяти ядра
ipc_perm
Заголовок
очереди
msgid_ds
msg_spot
msg_perm
msg_first
msg_last
msg_next
msg_next
msg_spot
struct msg
81

82.

Структуры данных
struct msgid_ds
msg_perm
Данные, хранящиеся в записи типа struct ipc_perm
msg_first
Указатель на первое (самое старое) сообщение в очереди
msg_last
Указатель на последнее (самое новое) сообщение в очереди
msg_cbyte
Общее число байт во всех сообщениях
msg_qnum
Общее число сообщений в очереди
msg_qbyte
Максимальное число байт, которое могут находится в
очереди
msg_lspid
Идентификатор процесса, который последним передал
сообщение
msg_lrpid
Идентификатор процесса, который последним прочитал
сообщение
msg_stime
Время поступления последнего сообщения
msg_rtime
Время прочтения последнего сообщения
msg_ctime
Время последнего изменения управляющих параметров
очереди
82

83.

struct msg
msg_type
целочисленный тип сообщения
msg_ts
количество байтов в сообщении
msg_spot
указатель на текст сообщения, который
хранится в области данных ядра
msg_next
указатель на следующую запись в очереди
сообщений (для последней записи NULL)
83

84.

Функции
#include <sys/types>
#include <sys/ipc.h>
#include <sys/message.h>
#include <sys/msg.h>
int msgget(key_t key, int flag);
int msgsnd(int msgfd, const void* msgPtr, int len, int flag);
int msgrcv(int msgfd, const void* msgPtr, int len, int mtype, int flag);
int msgctl(int msgfd, int cmd, struct msgid_ds* mbufPtr);
cmd
IPC_STAT – копировать управляющие параметры
IPC_SET – заменить управляющие параметры
IPC_RMID – удалить очередь
84

85.

/* mes.h */
#define PERM 0666
typedef struct msgbuf {
long mtype;
char buff[80];
} Message;
85

86.

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "mes.h"
int main()
{
Message message;
key_t key;
int msgid, length, n;
if((key = ftok("server",0))<0){ printf("Key error\n"); exit(1); }
message.mtype = 1L;
if((msgid = msgget(key,PERM | IPC_CREAT))<0){
printf("Queue error\n"); exit(1);
}
n = msgrcv(msgid, &message, sizeof(message), message.mtype, 0);
if(n>0) {
if(write(1, message.buff, n) != n) {
printf("Output error\n"); exit(1);
}
}
else {printf("Reding error\n"); exit(1);}
exit(0);
}
86

87.

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "mes.h"
int main()
{
Message message;
key_t key;
int msgid, length;
if((key = ftok("server",0))<0){
printf("Key error\n"); exit(1);
}
message.mtype = 1L;
if((msgid = msgget(key,0))<0){ printf("Queue error\n"); exit(1);}
if((length = sprintf(message.buff, "Example message\n")) < 0) {
printf("Copy error\n"); exit(1);
}
if(msgsnd(msgid, (void *) &message, length, 0) != 0) {
printf("Write error\n"); exit(1);
}
if(msgctl(msgid, IPC_RMID, 0) < 0) { printf("Delete errror\n"); exit(1);}
exit(0);
}
87

88.

Семафоры
Таблица
семафоров
struct sem
struct
semid_ds
struct sem
sem_base
88

89.

struct semid_ds {
struct ipc_perm sem_perm; //права доступа
struct sem *sem_base; //указатель на массив семафоров
ushort sem_nsems; //число семафоров в наборе
time_t sem_otime; //время последней операции над семафором
time_t sem_ctime; //время последнего изменения параметров
};
struct sem {
ushort semval; //целочисленное значение семафора
pid_t semid; //процесс, выполнявший операции над семафором в последний раз
ushort semncnt; //число ожидающих увеличения семафора процессов
ushort semzcnt; //число процессов, ожидающих обращения семафора в нуль
};
89

90.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int num_sem, int flag);
flag – SEM_R или SEM_A (R - read, A – Alter изменение)
int semop(int semfd, struct sembuf* opPtr, int len);
struct sem_buf {
short sem_num; //индекс семафора
short sem_op;
//операция над семафором
short sem_flg;
//флаги операции
};
90

91.

int semctl(int semfd; int num, int cmd, union semun arg);
union semun {
int val; //значение семафора
struct semid_ds *buf; //управляющие параметры семафора
ushort *array; //массив значений семафора
};
IPC_STAT
Копировать параметры набора в объект, по аргументу arg.buf
IPC_SET
Заменить управляющие параметры по адресу arg.buf
IPC_RMID
Удалить семафор из системы
GETALL
Скопировать значения семафоров в массив по arg.array
SETALL
Установить значения семафоров данными по указателю arg.array
GETVAL
Возвратить значения семафора с номером num
SETVAL
Установить значение семафора num по arg.val
GETPID
Возвратить идентификатор процесса, который выполнял
операции над семафором num
GETNCNT
Возвратить количество процессов, ожидающих увеличения
значения семафора
GETZCNT
Возвратить количество процессов, ожидающих обращения
семафора в нуль
91

92.

Значение sem_op
Действие
>0
Увеличить значение семафора на эту
величину
<0
Уменьшить значение семафора на эту
величину
0
Проверить равенство семафора 0
sem_op > 0 => v(s)
semval = semval + sem_op
Если есть процессы, ожидающие изменения этого семафора, то
они продолжат выполнение, когда новое значение удовлетворит их
условия.
sem_op = 0
Ожидание пока семафор не станет равным 0.
92

93.

sem_op <0 => p(s)
if (semval >= abs(sem_op))
semval = semval – abs(sem_op)
else
if (sem_flg & IPC_NOWAIT)
вернуть -1
else {
ожидание пока semval не станет >= abs(sem_op)
затем semval = semval – abs(sem_op)
}
93

94.

Разделяемая память
Пространство
пользователя
Процесс 1
Пространство
ядра
Процесс 2
общая
память
94

95.

shmget()
Память
Процесс 1
shmat()
Процесс 2
shmat()
95

96.

struct shmid_ds {
struct ipc_perm shm_perm; // режим и права доступа
size_t shm_size; //размер сегмента
pid_t shm_lpid; //процесс, выполнивший последнюю операцию
pid_t shm_cpid; //процесс создатель
shmatt_t shm_nattch; //текущее количество подключений
shmatt_t shm_cnattch; //количество подключений in-core
time_t shm_atime; //время последнего подключения
time_t shm_dtime; //время последнего отключения
time_t shm_ctime; //время последнего изменения shmid_ds
};
96

97.

Функции
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflag);
void *shmat(int shmid, const void *shmaddr, int flag);
по умолчанию следует задавать shmaddr равный NULL
память доступна для чтения и записи, при необходимости
следует использовать флаг RDONLY
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buff);
IPC_RMID – удаление сегмента разделяемой памяти
IPC_SET – установка полей shmid_ds по содержимому buff
IPC_STAT – копировать shmid_ds в buff
97

98.

/* share.h */
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHMKEY1 (key_t)010
#define SHMKEY2 (key_t)015
#define SEMKEY (key_t)020
#define SIZ 5*BUFSIZ
struct databuf {
int d_nread;
char d_buf[SIZ];
};
typedef union semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;
98

99.

#include "share.h"
#define IFLAGS (IPC_CREAT | IPC_EXCL)
#define ERR ((struct databuf *) -1)
static int shmid1, shmid2, semid;
struct sembuf p1 = {0,-1,0}, p2 = {1,-1,0};
struct sembuf v1 = {0,1,0}, v2 = {1,1,0};
void getseg(struct databuf **p1, struct databuf **p2)
{
if((shmid1 = shmget(SHMKEY1, sizeof(struct databuf), 0600|IFLAGS))==-1)
{perror("shmget1"); exit(1);}
if((shmid2 = shmget(SHMKEY2, sizeof(struct databuf), 0600|IFLAGS))==-1)
{perror("shmget2"); exit(1);}
if((*p1 = (struct databuf *)shmat(shmid1, 0, 0)) == ERR)
{perror("shmatt1"); exit(1);}
if((*p2 = (struct databuf *)shmat(shmid2, 0, 0)) == ERR)
{perror("shmatt1"); exit(1);}
}
99

100.

int getsem(void)
{
union semun x;
x.val = 0;
if((semid = semget(SEMKEY, 2, 0600|IFLAGS))==-1)
{perror("semget"); exit(1);}
if(semctl(semid, 0, SETVAL, x)==-1)
{perror("semctl"); exit(1);}
if(semctl(semid, 1, SETVAL, x)==-1)
{perror("semct2"); exit(1);}
return (semid);
}
void remobj(void)
{
if(shmctl(shmid1, IPC_RMID, NULL)==-1)
{perror("shmctl3"); exit(1);}
if(shmctl(shmid2, IPC_RMID, NULL)==-1)
{perror("shmctl4"); exit(1);}
if(semctl(semid, 0, IPC_RMID, NULL)==-1)
{perror("semctl"); exit(1);}
}
100

101.

void reader(int semid, struct databuf *buf1, struct databuf *buf2)
{
for(;;) {
buf1->d_nread=read(0,buf1->d_buf, SIZ);
semop(semid, &v1, 1);
semop(semid, &p2, 1);
if(buf1->d_nread<=0) return;
buf2->d_nread = read(0,buf2->d_buf,SIZ);
semop(semid, &v2, 1);
semop(semid, &p1, 1);
if(buf2->d_nread<=0) return;
}
}
101

102.

void writer(int semid, struct databuf *buf1, struct databuf *buf2)
{
for(;;) {
semop(semid, &p1, 1);
semop(semid, &v2, 1);
if(buf1->d_nread <= 0) return;
write(1, buf1->d_buf, buf1->d_nread);
semop(semid, &p2, 1);
semop(semid, &v1, 1);
if(buf2->d_nread <= 0) return;
write(1, buf2->d_buf, buf2->d_nread);
}
}
102

103.

main()
{
int semid;
pid_t pid;
struct databuf *buf1, *buf2;
semid = getsem();
getseg(&buf1, &buf2);
switch(pid = fork()) {
case -1:
perror("fork"); exit(1);
case 0:
writer(semid, buf1, buf2);
remobj();
break;
default:
reader(semid, buf1, buf2);
break;
}
exit(0);
}
103

104.

Процессы в ОС Windows
104

105.

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

106.

Потоки
• Каждый процесс начинается с одного потока, но
новые потоки могут создаваться динамически
• Потоки имеют состояния (готовый, работающий,
блокированный и т. д.) (у процессов состояний нет)
• Поток работает в пользовательском режиме, но когда
он обращается к системному вызову, то
переключается в режим ядра
• Любой поток может получить доступ ко всем
объектам его процесса
106

107.

Волокна
• Переключение потоков в операционной системе Windows
занимает довольно много времени, так как для этого
необходимо переключение в режим ядра
• Для предоставления сильно облегченного псевдопараллелизма
в Windows используются волокна, планируемые в пространстве
пользователя создавшей их программой
• У каждого потока может быть несколько волокон
• Когда волокно логически блокируется, оно помещается в
очередь блокированных волокон, после чего для работы
выбирается другое волокно в контексте того же потока.
• Операционная система не знает о смене волокон, так как все
тот же поток продолжает работу
• Так как операционная система ничего не знает о волокнах, то с
ними не связаны объекты исполняющей системы
• Для управления волокнами нет системных вызовов. Для этого
есть вызовы Win32 API. Они относятся к тем вызовам Win32
API, которые не обращаются к системным вызовам
107

108.

Создание процесса
1. Открывается файл образа (exe – файл)
2. Создается объект «процесс»
3. Создается первичный поток (стек,
контекст и объект «поток»)
4. Подсистема Windows уведомляется о
создании нового процесса и потока
5. Начинается выполнение первичного
потока
6. В контексте нового процесса и потока
инициируется адресное пространство и
начинается выполнение программы
108

109.


Новый процесс создается при помощи функции CreateProcess
Функция имеет 10 параметров:
1. Указатель на имя исполняемого файла.
2. Сама командная строка (непроанализированная).
3. Указатель на описатель защиты процесса.
4. Указатель на описатель защиты для начального потока.
5. Бит, управляющий наследованием дескрипторов.
6. Разнообразные флаги (например, режим ошибки, приоритет,
отладка, консоли).
7. Указатель на строки окружения.
8. Указатель на имя текущего рабочего каталога нового процесса.
9. Указатель на структуру, описывающую начальное окно на экране.
10. Указатель на структуру, возвращающую вызывающему процессу
18 значений.
109

110.

• В операционной системе Windows не
поддерживается какой-либо иерархии процессов,
например «родительский - дочерний».
• Все созданные процессы равны
• Один из 18 параметров, возвращаемых
вызывающему процессу, представляет собой
дескриптор нового процесса (что предоставляет
контроль над новым процессом)
• Существует негласная иерархия, заключающаяся в
том, кто чьим дескриптором владеет
• Эти дескрипторы не могут напрямую передаваться
другим процессам
• У процесса есть способ создать дубликат
дескриптора. Дубликат дескриптора может быть
передан другому процессу и использоваться им,
поэтому неявная иерархия процессов может
просуществовать недолго.
110

111.

Создание потока
• Каждый процесс в Windows создается с одним потоком
• Процесс может позднее создать дополнительные
потоки
• Создание потока производится вызовом CreateThread
с шестью параметрами:
• 1. Описатель защиты (необязательный).
• 2. Начальный размер стека.
• 3. Адрес запуска.
• 4. Параметр, задаваемый пользователем.
• 5. Начальное состояние потока (готовый или
блокированный).
• 6. Идентификатор потока.
111

112.

Планирование процессов
• В операционной системе Windows нет центрального
потока планирования.
• Когда какой-либо поток не может более выполняться,
этот поток сам переходит в режим ядра и запускает
планировщика
• Текущий поток выполняет программу планировщика
при одном из следующих условий:
– 1) поток блокируется на семафоре, мьютексе, событии,
операции ввода-вывода и т. д;
– 2) поток сигнализирует каким-либо объектом (например,
выполняет операцию up на семафоре);
– 3) истекает квант времени работающего потока.
• Планировщик также вызывается при еще двух
условиях:
– Завершается операция ввода-вывода.
– Истекает ожидание таймера.
112

113.

Приоритеты процессов
Классы
приоритетов
реального времени
высокий
выше нормы
нормальный
ниже нормы
неработающий
Приоритеты
потоков
критичный ко времени
самый высокий
выше нормы
нормальный
ниже нормы
самый низкий
неработающий
113

114.

Взаимодействие процессов
• каналы
– байтовый режим
– режим сообщений
именованные каналы
почтовые ящики
сокеты
вызов удаленной процедуры
совместно используемые файлы
114

115.

Механизмы синхронизации
семафоры
мьютексы
критические секции
события
115

116.

Функции для работы с механизмами синхронизации
CreateSemaphore
Создать новый семафор
OpenSemaphore
Открыть существующий семафор
CreateMutex
Создать новый мьютекс
OpenMutex
Открыть существующий мьютекс
WaitForSingleObject
Блокироваться на одном семафоре, мьютексе и т. д.
WaitForMultipleObjects
Блокироваться на множестве объектов, чьи
дескрипторы перечисляются
PulseEvent
Перевести событие в сигнализирующее состояние,
а затем вернуть в несигнализирующее
ReleaseMutex
Освободить мьютекс, чтобы другой поток мог его
захватить
ReleaseSemaphore
Увеличить на единицу счетчик семафора
EnterCriticalSection
Захватить блокировку для критической секции
LeaveCriticalSection
Освободить блокировку для критической секции
116
English     Русский Правила