В материалах предыдущего семинара речь шла о необходимости синхронизации работы процессов для их корректного взаимодействия через разделяемую память. Как упоминалось в лекции 6, одним из первых механизмов, предложенных для синхронизации поведения процессов, стали семафоры, концепцию которых описал Дейкстра (Dijkstra) в 1965 году. При разработке средств {P, V}, предложенного Дейкстрой. Он включает три операции:
A(S, n) – увеличить S на величину n ; D(S, n) – пока S < n, процесс блокируется. Далее S = S - n; Z(S) – процесс блокируется до тех пор, пока S не станет равным 0 Изначально все IPC-семафоры инициируются нулевым значением.
Мы видим, что классической операции P(S) соответствует операция , а классической операции V(S) соответствует операция . Аналогом ненулевой инициализации сразу после создания семафора S, с обеспечением атомарности создания семафора и ее выполнения посредством другого семафора. Мы показали, что классические семафоры реализуются через P(S) и V(S), мы не сумеем реализовать операцию .
Поскольку IPC-семафоры являются составной частью средств ftok(). Для совершения операций над семафорами системным вызовам в качестве параметра передаются IPC- дескрипторы семафоров, однозначно идентифицирующих их во всей вычислительной системе, а вся информация о семафорах располагается в адресном пространстве ядра операционной системы. Это позволяет организовывать через семафоры взаимодействие процессов, даже не находящихся в системе одновременно.
В целях экономии системных ресурсов операционная система UNIX позволяет создавать не по одному семафору для каждого конкретного значения ключа, а связывать с ключом целый shmget() для разделяемой памяти, который возвращает значение IPC-дескриптора для этого shmget(), shmat(), shmdt() "), что и для разделяемой памяти. Вновь созданные семафоры инициируются нулевым значением.
Системный вызов semget() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems,
int semflg);
Описание системного вызова Системный вызов Параметр Параметр Параметр
0400 — разрешено чтение для пользователя, создавшего массив0200 — разрешена запись для пользователя, создавшего массив0040 — разрешено чтение для группы пользователя, создавшего массив0020 — разрешена запись для группы пользователя, создавшего массив0004 — разрешено чтение для всех остальных пользователей0002 — разрешена запись для всех остальных пользователейВновь созданные семафоры инициируются нулевым значением. Возвращаемое значение Системный вызов возвращает значение дескриптора |
A, D и Z над семафорами из
A(S1,5) и Z(S2) в одном вызове и оказалось, что S2 != 0, то S1 не будет изменено до тех пор, пока значение S2 не станет равным 0. Порядок выполнения операций в случае, когда процесс не переходит в состояние ожидание, не определен. Так, например, при одновременном выполнении операций A(S1,1) и D(S2,1) в случае S2 > 1 неизвестно, что произойдет раньше – уменьшится S2 или увеличится S1. Если порядок для вас важен, лучше применить несколько вызовов вместо одного.struct sembuf с размерностью, равной определенному количеству семафоров (если операция совершается только над одним семафором, можно, естественно, обойтись просто переменной). Каждый элемент этого массива будет соответствовать операции над одним семафором.sem_flg каждого элемента нужно занести значение 0 (другие значения флагов в семинарах мы рассматривать не будем). В поля sem_num и sem_op следует занести номера семафоров в 0. Если у вас в 0. Операции кодируются так: A(S,n) значение поля sem_op должно быть равно n ; D(S,n) значение поля sem_op должно быть равно –n ; Z(S) значение поля sem_op должно быть равно 0. semop() указать адрес заполненного Системный вызов semop() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops,
int nsops);
Описание системного вызова
Параметр Каждый из short sem_num — номер семафора в массиве IPC семафоров (нумеруются, начиная с 0 );short sem_op — выполняемая операция;short sem_flg — флаги для выполнения операции. В нашем курсе всегда будем считать эту переменную равной 0.Значение элемента структуры A(S,n) значение должно быть равно n ;D(S,n) значение должно быть равно -n ;Z(S) значение должно быть равно 0.Семантика системного вызова подразумевает, что все операции будут в реальности выполнены над семафорами только перед успешным возвращением из системного вызова. Если при выполнении операций В этом случае происходит возврат из системного вызова с констатацией ошибочной ситуации. Возвращаемое значение Системный вызов возвращает значение |
Для иллюстрации сказанного рассмотрим простейшие программы, синхронизирующие свои действия с помощью семафоров
/* Программа 08-1a.c для иллюстрации работы с
семафорами */
/* Эта программа получает доступ к одному системному семафору,
ждет, пока его значение не станет больше или равным 1
после запусков программы 08-1b.c,а затем уменьшает его на 1*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
int main()
{
int semid; /* IPC дескриптор для массива IPC
семафоров */
char pathname[] = "08-1a.c"; /* Имя файла,
использующееся для генерации ключа. Файл с таким
именем должен существовать в текущей директории */
key_t key; /* IPC ключ */
struct sembuf mybuf; /* Структура для задания
операции над семафором */
/* Генерируем IPC-ключ из имени файла 08-1a.c в текущей
директории и номера экземпляра массива семафоров 0 */
if((key = ftok(pathname,0)) < 0){
printf("Can\'t generate key\n");
exit(-1);
}
/* Пытаемся получить доступ по ключу к массиву
семафоров, если он существует, или создать его из одного
семафора, если его еще не существует, с правами доступа
read write для всех пользователей */
if((semid = semget(key, 1, 0666 | IPC_CREAT)) < 0){
printf("Can\'t get semid\n");
exit(-1);
}
/* Выполним операцию D(semid1,1) для нашего массива
семафоров. Для этого сначала заполним нашу структуру.
Флаг, как обычно, полагаем равным 0. Наш массив семафоров
состоит из одного семафора с номером 0. Код операции -1.*/
mybuf.sem_op = -1;
mybuf.sem_flg = 0;
mybuf.sem_num = 0;
if(semop(semid, mybuf, 1) < 0){
printf("Can\'t wait for condition\n");
exit(-1);
}
printf("Condition is present\n");
return 0;
}
/* Программа 08-1b.c для иллюстрации работы с
семафорами */
/* Эта программа получает доступ к одному системному семафору
и увеличивает его на 1*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
int main()
{
int semid; /* IPC дескриптор для массива IPC
семафоров */
char pathname[] = "08-1a.c"; /* Имя файла,
использующееся для генерации ключа. Файл с таким
именем должен существовать в текущей директории */
key_t key; /* IPC ключ */
struct sembuf mybuf; /* Структура для задания операции
над семафором */
/* Генерируем IPC ключ из имени файла 08-1a.c в текущей
директории и номера экземпляра массива семафоров 0 */
if((key = ftok(pathname,0)) < 0){
printf("Can\'t generate key\n");
exit(-1);
}
/* Пытаемся получить доступ по ключу к массиву
семафоров, если он существует, или создать его из
одного семафора, если его еще не существует, с правами доступа
read write для всех пользователей */
if((semid = semget(key, 1, 0666 | IPC_CREAT)) < 0){
printf("Can\'t get semid\n");
exit(-1);
}
/* Выполним операцию A(semid1,1) для нашего массива
семафоров. Для этого сначала заполним нашу структуру.
Флаг, как обычно, полагаем равным 0. Наш массив
семафоров состоит из одного семафора с номером 0.
Код операции 1.*/
mybuf.sem_op = 1;
mybuf.sem_flg = 0;
mybuf.sem_num = 0;
if(semop(semid, mybuf, 1) < 0){
printf("Can\'t wait for condition\n");
exit(-1);
}
printf("Condition is set\n");
return 0;
}
Первая программа выполняет над семафором S операцию , вторая программа выполняет над тем же семафором операцию . Если семафора в системе не существует, любая программа создает его перед выполнением операции. Поскольку при создании семафор всегда инициируется 0, то программа 1 может работать без блокировки только после запуска программы 2. Наберите программы, сохраните под именами 08-1а.с и 08-1b.c cоответственно, откомпилируйте и проверьте правильность их поведения.
Измените программы из предыдущего раздела так, чтобы первая программа могла работать без блокировки после не менее 5 запусков второй программы.
Как мы видели в примерах, ipcs и ipcrm, рассмотренными в материалах предыдущего семинара. Команда ipcrm в этом случае должна иметь вид
ipcrm sem <IPC идентификатор>
Для этой же цели мы можем применять системный вызов , который умеет выполнять и другие операции над
Системный вызов semctl() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd,
union semun arg);
Описание системного вызова Системный вызов В нашем курсе мы будем применять системный вызов В качестве параметра Если какие-либо процессы находились в состоянии ожидание для семафоров из удаляемого массива при выполнении системного вызова Возвращаемое значение Системный вызов возвращает значение |
В материалах семинаров 6–7 было показано, что любые неатомарные операции, связанные с изменением содержимого разделяемой памяти, представляют собой критическую секцию процесса или нити исполнения. Модифицируйте программы из раздела "Необходимость синхронизации процессов и нитей исполнения, использующих общую память" семинаров 6–7, которые иллюстрировали некорректную работу через разделяемую память, обеспечив с помощью семафоров взаимоисключения для их правильной работы.
В материалах семинара 5, когда речь шла о связи родственных процессов через pipe, отмечалось, что pipe является однонаправленным каналом связи, и что для организации связи через один pipe в двух направлениях необходимо использовать механизмы взаимной синхронизации процессов. Организуйте двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации семафоры, модифицировав программу из раздела "Прогон программы для организации однонаправленной связи между родственными процессами через pipe" семинара 5.
В стандарте POSIX вводятся другие семафоры, полностью аналогичные семафорам Дейкстры. Для инициализации значения таких семафоров применяется функция sem_init(), аналогом операции P служит функция sem_wait(), а аналогом операции V – функция sem_post(). К сожалению, в Linux такие семафоры реализованы только для нитей исполнения одного процесса, и поэтому подробно мы на них останавливаться не будем.
В материалах предыдущего семинара речь шла о необходимости синхронизации работы процессов для их корректного взаимодействия через разделяемую память. Как упоминалось в лекции 6, одним из первых механизмов, предложенных для синхронизации поведения процессов, стали семафоры, концепцию которых описал Дейкстра (Dijkstra) в 1965 году. При разработке средств {P, V}, предложенного Дейкстрой. Он включает три операции:
A(S, n) – увеличить S на величину n ; D(S, n) – пока S < n, процесс блокируется. Далее S = S - n; Z(S) – процесс блокируется до тех пор, пока S не станет равным 0 Изначально все IPC-семафоры инициируются нулевым значением.
Мы видим, что классической операции P(S) соответствует операция , а классической операции V(S) соответствует операция . Аналогом ненулевой инициализации сразу после создания семафора S, с обеспечением атомарности создания семафора и ее выполнения посредством другого семафора. Мы показали, что классические семафоры реализуются через P(S) и V(S), мы не сумеем реализовать операцию .
Поскольку IPC-семафоры являются составной частью средств ftok(). Для совершения операций над семафорами системным вызовам в качестве параметра передаются IPC- дескрипторы семафоров, однозначно идентифицирующих их во всей вычислительной системе, а вся информация о семафорах располагается в адресном пространстве ядра операционной системы. Это позволяет организовывать через семафоры взаимодействие процессов, даже не находящихся в системе одновременно.
В целях экономии системных ресурсов операционная система UNIX позволяет создавать не по одному семафору для каждого конкретного значения ключа, а связывать с ключом целый shmget() для разделяемой памяти, который возвращает значение IPC-дескриптора для этого shmget(), shmat(), shmdt() "), что и для разделяемой памяти. Вновь созданные семафоры инициируются нулевым значением.
Системный вызов semget() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems,
int semflg);
Описание системного вызова Системный вызов Параметр Параметр Параметр
0400 — разрешено чтение для пользователя, создавшего массив0200 — разрешена запись для пользователя, создавшего массив0040 — разрешено чтение для группы пользователя, создавшего массив0020 — разрешена запись для группы пользователя, создавшего массив0004 — разрешено чтение для всех остальных пользователей0002 — разрешена запись для всех остальных пользователейВновь созданные семафоры инициируются нулевым значением. Возвращаемое значение Системный вызов возвращает значение дескриптора |
A, D и Z над семафорами из
A(S1,5) и Z(S2) в одном вызове и оказалось, что S2 != 0, то S1 не будет изменено до тех пор, пока значение S2 не станет равным 0. Порядок выполнения операций в случае, когда процесс не переходит в состояние ожидание, не определен. Так, например, при одновременном выполнении операций A(S1,1) и D(S2,1) в случае S2 > 1 неизвестно, что произойдет раньше – уменьшится S2 или увеличится S1. Если порядок для вас важен, лучше применить несколько вызовов вместо одного.struct sembuf с размерностью, равной определенному количеству семафоров (если операция совершается только над одним семафором, можно, естественно, обойтись просто переменной). Каждый элемент этого массива будет соответствовать операции над одним семафором.sem_flg каждого элемента нужно занести значение 0 (другие значения флагов в семинарах мы рассматривать не будем). В поля sem_num и sem_op следует занести номера семафоров в 0. Если у вас в 0. Операции кодируются так: A(S,n) значение поля sem_op должно быть равно n ; D(S,n) значение поля sem_op должно быть равно –n ; Z(S) значение поля sem_op должно быть равно 0. semop() указать адрес заполненного Системный вызов semop() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops,
int nsops);
Описание системного вызова
Параметр Каждый из short sem_num — номер семафора в массиве IPC семафоров (нумеруются, начиная с 0 );short sem_op — выполняемая операция;short sem_flg — флаги для выполнения операции. В нашем курсе всегда будем считать эту переменную равной 0.Значение элемента структуры A(S,n) значение должно быть равно n ;D(S,n) значение должно быть равно -n ;Z(S) значение должно быть равно 0.Семантика системного вызова подразумевает, что все операции будут в реальности выполнены над семафорами только перед успешным возвращением из системного вызова. Если при выполнении операций В этом случае происходит возврат из системного вызова с констатацией ошибочной ситуации. Возвращаемое значение Системный вызов возвращает значение |
Для иллюстрации сказанного рассмотрим простейшие программы, синхронизирующие свои действия с помощью семафоров
/* Программа 08-1a.c для иллюстрации работы с
семафорами */
/* Эта программа получает доступ к одному системному семафору,
ждет, пока его значение не станет больше или равным 1
после запусков программы 08-1b.c,а затем уменьшает его на 1*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
int main()
{
int semid; /* IPC дескриптор для массива IPC
семафоров */
char pathname[] = "08-1a.c"; /* Имя файла,
использующееся для генерации ключа. Файл с таким
именем должен существовать в текущей директории */
key_t key; /* IPC ключ */
struct sembuf mybuf; /* Структура для задания
операции над семафором */
/* Генерируем IPC-ключ из имени файла 08-1a.c в текущей
директории и номера экземпляра массива семафоров 0 */
if((key = ftok(pathname,0)) < 0){
printf("Can\'t generate key\n");
exit(-1);
}
/* Пытаемся получить доступ по ключу к массиву
семафоров, если он существует, или создать его из одного
семафора, если его еще не существует, с правами доступа
read write для всех пользователей */
if((semid = semget(key, 1, 0666 | IPC_CREAT)) < 0){
printf("Can\'t get semid\n");
exit(-1);
}
/* Выполним операцию D(semid1,1) для нашего массива
семафоров. Для этого сначала заполним нашу структуру.
Флаг, как обычно, полагаем равным 0. Наш массив семафоров
состоит из одного семафора с номером 0. Код операции -1.*/
mybuf.sem_op = -1;
mybuf.sem_flg = 0;
mybuf.sem_num = 0;
if(semop(semid, mybuf, 1) < 0){
printf("Can\'t wait for condition\n");
exit(-1);
}
printf("Condition is present\n");
return 0;
}
/* Программа 08-1b.c для иллюстрации работы с
семафорами */
/* Эта программа получает доступ к одному системному семафору
и увеличивает его на 1*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
int main()
{
int semid; /* IPC дескриптор для массива IPC
семафоров */
char pathname[] = "08-1a.c"; /* Имя файла,
использующееся для генерации ключа. Файл с таким
именем должен существовать в текущей директории */
key_t key; /* IPC ключ */
struct sembuf mybuf; /* Структура для задания операции
над семафором */
/* Генерируем IPC ключ из имени файла 08-1a.c в текущей
директории и номера экземпляра массива семафоров 0 */
if((key = ftok(pathname,0)) < 0){
printf("Can\'t generate key\n");
exit(-1);
}
/* Пытаемся получить доступ по ключу к массиву
семафоров, если он существует, или создать его из
одного семафора, если его еще не существует, с правами доступа
read write для всех пользователей */
if((semid = semget(key, 1, 0666 | IPC_CREAT)) < 0){
printf("Can\'t get semid\n");
exit(-1);
}
/* Выполним операцию A(semid1,1) для нашего массива
семафоров. Для этого сначала заполним нашу структуру.
Флаг, как обычно, полагаем равным 0. Наш массив
семафоров состоит из одного семафора с номером 0.
Код операции 1.*/
mybuf.sem_op = 1;
mybuf.sem_flg = 0;
mybuf.sem_num = 0;
if(semop(semid, mybuf, 1) < 0){
printf("Can\'t wait for condition\n");
exit(-1);
}
printf("Condition is set\n");
return 0;
}
Первая программа выполняет над семафором S операцию , вторая программа выполняет над тем же семафором операцию . Если семафора в системе не существует, любая программа создает его перед выполнением операции. Поскольку при создании семафор всегда инициируется 0, то программа 1 может работать без блокировки только после запуска программы 2. Наберите программы, сохраните под именами 08-1а.с и 08-1b.c cоответственно, откомпилируйте и проверьте правильность их поведения.
Измените программы из предыдущего раздела так, чтобы первая программа могла работать без блокировки после не менее 5 запусков второй программы.
Как мы видели в примерах, ipcs и ipcrm, рассмотренными в материалах предыдущего семинара. Команда ipcrm в этом случае должна иметь вид
ipcrm sem <IPC идентификатор>
Для этой же цели мы можем применять системный вызов , который умеет выполнять и другие операции над
Системный вызов semctl() Прототип системного вызова #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd,
union semun arg);
Описание системного вызова Системный вызов В нашем курсе мы будем применять системный вызов В качестве параметра Если какие-либо процессы находились в состоянии ожидание для семафоров из удаляемого массива при выполнении системного вызова Возвращаемое значение Системный вызов возвращает значение |
В материалах семинаров 6–7 было показано, что любые неатомарные операции, связанные с изменением содержимого разделяемой памяти, представляют собой критическую секцию процесса или нити исполнения. Модифицируйте программы из раздела "Необходимость синхронизации процессов и нитей исполнения, использующих общую память" семинаров 6–7, которые иллюстрировали некорректную работу через разделяемую память, обеспечив с помощью семафоров взаимоисключения для их правильной работы.
В материалах семинара 5, когда речь шла о связи родственных процессов через pipe, отмечалось, что pipe является однонаправленным каналом связи, и что для организации связи через один pipe в двух направлениях необходимо использовать механизмы взаимной синхронизации процессов. Организуйте двустороннюю поочередную связь процесса-родителя и процесса-ребенка через pipe, используя для синхронизации семафоры, модифицировав программу из раздела "Прогон программы для организации однонаправленной связи между родственными процессами через pipe" семинара 5.
В стандарте POSIX вводятся другие семафоры, полностью аналогичные семафорам Дейкстры. Для инициализации значения таких семафоров применяется функция sem_init(), аналогом операции P служит функция sem_wait(), а аналогом операции V – функция sem_post(). К сожалению, в Linux такие семафоры реализованы только для нитей исполнения одного процесса, и поэтому подробно мы на них останавливаться не будем.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.