Материал: metod_ukaz

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Если в имени функции присутствует символ ‘l’, то аргументы arg командной строки передаются в виде списка arg0, arg1.... argn, NULL.

Если в имени функции присутствует символ ‘v’, то аргументы командной строки передаются в виде массива argv[]. Отдельные аргументы адресуются через argv[0], argv[1], ..., argv[n]. Последний аргумент (argv [n]) должен быть NULL.

Если в имени функции присутствует символ ‘e’, то последним аргументом функции является массив переменных среды envp[].

Если в имени функции присутствует символ ‘p’, то программа с именем file ищется не только в текущем каталоге, но и в каталогах, определенных переменной среды PATH.

Если в имени функции отсутствует символ ‘p’, то программа с именем path ищется только в текущем каталоге, или имя path должно указывать полный путь к файлу.

Функция execve(), является основной в семействе, остальные функции обеспечивают интерфейс к ней.

В случае успешного выполнения вызова функция не возвращает никакого результата. В случае ошибки возвращается -1, а глобальной переменной errno присваивается значение в соответствии с видом ошибки.

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

sem_t *sem_open(const char *name,

int oflag,

mode_t mode,

unsigned int value),

где:

name – имя семафора;

oflag – флаг, управляющий операцией создания семафора, при создании семафора необходимо указать флаг O_CREAT;

mode – права доступа к семафору, могут быть установлены, например, в 0644;

value – начальное состояние семафора.

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

int sem_close(sem_t *sem).

При входе в критический участок необходимо вызвать функцию:

int sem_wait(sem_t *sem).

При выходе из критического участка необходимо вызвать функцию:

int sem_post(sem_t *sem).

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

int sem_unlink(const char *name).

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

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

где:

key_t key - ключ для создания уникального объекта;

int nsems – количество создаваемых семафоров;

int semflg- флаги управления доступом к семафору.

Ключ должен быть получен функцией:

key_t ftok(const char *pathname, int proj_id);

где:

const char *pathname – имя существующего файла;

int proj_id – идентификатор проекта.

При задании в двух программах одинакового имени файла и одинакового идентификатора проекта функция возвращает в этих программах одинаковый ключ.

Захват и освобождение семафора выполняется одной и той же функцией следующего вида:

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

где:

int semid – идентификатор семафора, возвращаемый функцией semget();

struct sembuf *sops – указатель на структуру, определяющую операции, которые надо выполнить с семафором;

unsigned nsops – количество операций.

Структура struct sembuf имеет следующий вид:

struct sembuf {

short sem_num;

short sem_op;

short sem_flg;

};

где:

short sem_num – номер семафора, над которым делается операция;

short sem_op – вид операции над семафором;

short sem_flg – флаги операции.

Три вида операций могут быть выполнены над семафором:

  1. если sem_op = 0, то процесс ждет, пока семафор не обнулится;

  2. если sem_op > 0, то текущее значение семафора увеличивается на величину sem_op;

  3. если sem_op < 0, то процесс ждет, пока значение семафора не станет или равным абсолютной величине sem_op. Затем абсолютная величина sem_op вычитается из значения семафора.

Пусть значение семафора 0 означает, что ресурс свободен, а значение 1 означает, что ресурс занят.

Создадим структуру следующего вида:

struct sembuf lock[2] = {

0,0,0, //ждать обнуления семафора

0,1,0 //увеличить значение семафора на 1

};

Тогда следующая операция будет захватывать ресурс:

semop(semid,&lock[0],2);

Введем структуру следующего вида:

struct sembuf unlock[1] = {

0,-1,0, //обнулить семафор

};

Тогда следующая операция будет освобождать ресурс:

semop(semid,&unlock[0],1);

По окончанию работы с семафором его необходимо удалить функцией:

int semctl(int semid, int semnum, int cmd);

где:

int semid – идентификатор удаляемой группы семафоров;

int semnum – номер семафора – игнорируется для команды IPC_RMID;

int cmd – команда, которая в случае удаления принимает значение IPC_RMID.

Указания к выполнению работы

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

Необходимо выбрать общий ресурс - файл и осуществлять запись данных в него из двух программ.

Обе программы должны создать (или открыть, если создан) один и тот же именованный семафор, должны создать (или открыть, если создан) один и тот же файл, но записывать в файл разные символы.

Необходимо убедиться, что в случае отсутствия именованного семафора процессы выводят символы в файл в произвольном порядке, например:

1212121212121212121212121212121212121212121212121212121212121.

В случае использования именованного семафора процессы выводят символы в файл в определенном порядке, например:

111111111122222222221111111111222222222211111111112222222222.

Использовать функции входа в критический участок с блокировкой и без блокировки.

Студенты используют семафоры стандарта POSIX для координации доступа к ресурсу.

Шаблон одной из программ представлен ниже. Вторая программа отличается от первой выводом в файл другого символа

объявить флаг завершения потока;

объявить идентификатор именованного семафора;

объявить дескриптор файла;

функция потока()

{

объявить переменную типа символ и присвоить ей значение ‘1’;

пока (флаг завершения потока не установлен)

{

захватить именованный семафор;

в цикле несколько раз выполнять

{

выводить символ в файл;

задержать на время;

}

освободить именованный семафор;

задержать на время;

}

}

основная программа()

{

создать (или открыть, если существует) именованный семафор;

создать (или открыть, если существует) файл;

создать поток из функции потока;

ждать нажатия клавиши;

установить флаг завершения потока;

ждать завершения потока;

закрыть файл;

закрыть именованный семафор;

удалить именованный семафор;

}

Вопросы для самопроверки

  1. Какие программные интерфейсы для именованных семафоров существуют?

  2. В чем отличие именованных семафоров от неименованных семафоров?

  3. Дайте сравнительную характеристику программных интерфейсов семафоров.

  4. Как реализовать определенную очередность записи данных в файл с помощью именованного семафора (например, первый процесс всегда первым начинает запись файл)?

  5. Опишите действия, которые выполняются над именованным семафором при вызове операций sem_wait() и sem_post().

  6. Какими операциями с именованным семафором можно осуществить

проверку занятости ресурса без блокирования процесса?

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

6. Взаимодействие процессов через разделяемую память

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

Общие сведения

В стандарте POSIX участок разделяемой памяти создается следующим вызовом:

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

где:

name – имя участка разделяемой памяти;

oflag – флаги, определяющие тип создаваемого участка разделяемой памяти;

mode – права доступа к участку разделяемой памяти.

Установка размера участка разделяемой памяти производится следующим вызовом:

int ftruncate(int fd, off_t length),

где:

fd - дескриптор разделяемой памяти, полученный как результат вызова функции shm_open();

length – требуемый размер разделяемой памяти.

Отображение разделяемой памяти на локальный адрес создается вызовом:

void *mmap(void *addr,

size_t length,

int prot,

int flags,

int fd,

off_t offset),

где:

addr - начальный адрес отображения;

length - размер отображения;

prot – параметр, определяющий права чтения/записи отображения;

flags – параметр, определяющий правила видимости отображения процессами;

fd - дескриптор разделяемой памяти;

offset – смещение на участке разделяемой памяти относительно начального адреса.

Удаление отображения разделяемой памяти на локальный адрес производится вызовом:

int munmap(void *addr, size_t length),

где:

addr – локальный адрес отображения;

length - размер отображения.

Закрытие участка разделяемой памяти производится вызовом:

int close(int fd),

где:

fd - дескриптор разделяемой памяти.

Удаление участка разделяемой памяти производится вызовом:

int shm_unlink(const char *name),

где:

name – имя участка разделяемой памяти.

В стандарте SVID участок разделяемой памяти создается вызовом:

int shmget(key_t key, int size, int shmflg);

где:

key_t key – ключ, получаемый функцией ftok();

int size – требуемый размер памяти;

int shmflg – флаги, задающие права доступа к памяти, например, 0644|IPC_CREAT.

После создания участка разделяемой памяти его необходимо подсоединить к адресному пространству процесса. Это делается вызовом:

void *shmat(int shmid, const void *shmaddr, int shmflg);

где:

int shmid – идентификатор сегмента;

const void *shmaddr – адрес памяти;

int shmflg - флаги, задающие права доступа к памяти.

После использования памяти ее необходимо отсоединить от адресного пространства процесса вызовом:

int shmdt(const void *shmaddr);

где:

const void *shmaddr – адрес памяти;

А затем удалить вызовом:

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

где:

int shmid – идентификатор сегмента;

int cmd – код команды, для удаления используется IPC_RMID;

struct shmid_ds *buf – структура для хранения информации о сегменте разделяемой памяти, в случае удаления не используется.

Источник: https://studfile.net/preview/16676187/