Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Part2.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
212.49 Кб
Скачать

Использование класса boost::shared_mutex

Зачастую простой мьютекс, защищающий память, неоптимален. Например, в онлайн-игре список игровых комнат изменяется нечасто — когда кто-то из игроков решает открыть новую комнату, например, раз в несколько секунд. Считывается же он за одну секунду десятки раз, и выстраивать клиентов в очередь для этого не имеет смысла.

Подобные механизмы (так называемая блокировка чтения-записи) существуют во многих языках программирования и библиотеках. Например.

Embarcadero Delphi: IMultiReadExclusiveWrite.

POSIX: pthread_rwlock_t.

Java: ReadWriteLock, ReentrantReadWriteLock.

.NET Framework: System.Threading.ReaderWriterLockSlim.

Boost: boost::shared_mutex.

Пример (читатель)

boost::shared_mutex g_Mutex;

void reader_proc()

{ // . . .

g_Mutex.lock_shared();

// Чтение

g_Mutex.unlock_shared();

// . . .

}

Пример (писатель)

void writer_proc()

{ // . . .

g_Mutex.lock();

// Запись

g_Mutex.unlock();

// . . .

}

Межпроцессное взаимодействие

Объекты синхронизации

Используются для работы с разл. процессами.

объекты синхронизации, используемые для взаимодействия между процессами

- События (Windows API)

- Условные переменные (POSIX) (не явл. объектом ядра, поэтому нельзя использовать для разделения между процессами)

- Мьютексы

- Семафоры

События Windows API

HANDLE WINAPI CreateEvent (

__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,

__in BOOL bManualReset,

__in BOOL bInitialState,

__in_opt LPCTSTR lpctszName //не обязательно указатель на строку, опр-ет имя события );

HANDLE WINAPI OpenEvent (

__in DWORD dwDesiredAccess,

__in BOOL bInheritHandle,

__in LPCTSTR lpctszName // -- - -- );

Мьютексы Windows API

HANDLE WINAPI CreateMutex (

__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes, //Атрибуты безопасности

__in BOOL bInitialOwner, //Флаг начального владельца – свободен или занят

__in_opt LPCTSTR lpctszName //Имя );

HANDLE WINAPI OpenMutex (

__in DWORD dwDesiredAccess, //Константа, опр-ет, что хотим сделать (чтобы использовать мьютекс, необх. только синхронизировать права доступа

__in BOOL bInheritHandle, //Определяет, можно ли дескриптор наследовать в дочерних процессах

__in LPCTSTR lpctszName );

Семафоры Windows API

HANDLE WINAPI CreateSemaphore (

__in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

__in LONG lInitialCount, //Начальное

__in LONG lMaximumCount, //Максимальное значение счетчика

__in_opt LPCTSTR lpctszName );

HANDLE WINAPI OpenSemaphore (

__in DWORD dwDesiredAccess,

__in BOOL bInheritHandle,

__in LPCTSTR lpctszName );

Использование разделяемых событий в Windows API

Пример (event.h)

#ifndef EVENT_H__

#define EVENT_H__

#define MY_IPC_EVENT_NAME \

"event_CB44CFBF 52C3 487A 95A0 1233F5A4393C"

#define MY_IPC_MUTEX_NAME \

"mutex_0DF33C8C 71FF 4358 B10A AD7F0B7484F7"

#endif // EVENT_H__

//GUID (глобальный уникальный идентификатор)

Пример (main_parent.cpp)

#include "event.h"

// . . .

int main()

{ HANDLE hEvent = CreateEvent(

NULL, // lpEventAttributes

FALSE, // bManualReset

FALSE, // bInitialState

_T(MY_IPC_EVENT_NAME)); // lpctszName

// . . .

}

Строковая константа определена в заголовочном файле

Клиент гарантировано открылся после сервера

Пример (main_child.cpp)

#include "event.h"

// . . .

int main()

{ HANDLE hEvent = OpenEvent(

SYNCHRONIZE, // dwDesiredAccess КОНСТАНТА

FALSE, // bInheritHandle

_T(MY_IPC_EVENT_NAME)); // lpctszName //макрос, если объявлен юникод

// . . .

}

работает как с utf-16 как с юникодом, define _T(s) добавляет букву L (L##S), т.е. находится в более широкой кодировке)

функции принимают все строки в формате unicode

Способы доступа к объектам ядра в других процессах

Средства межпроцессного обмена дескрипторами

- Именованные объекты;

- Наследование дескрипторов дочерними процессами;

- Дублирование дескрипторов (DuplicateHandle()).

Семафоры POSIX

#include <fcntl.h>

#include <sys/stat.h>

#include <semaphore.h>

int sem_init (

sem_t *pSem,

int nPShared, //Равен 0, если хотим сделать локальным для одного процесса, не 0 – разделять между разными (fork()ed)

unsigned int uValue);

sem_t *sem_open(

const char *pcszName, int nOFlag,

/* unsigned long ulMode, unsigned int uValue */ ...);

возможные значения флагов параметров функции sem_open()

nOFlag

O_CREAT – задает операцию создания. Если сброшен – только пытается найти ?. Передается две доп. переменные.

O_EXCL – эксклюзивный. Пытается создать. Если уже существует, то возвр. NULL в качестве указателя. Если флаг не указан, в комбинации с O_CREAT возвращает ук-ль на начало

ulMode

S_IRWXU S_IRUSR S_IWUSR S_IXUSR

S_IRWXG S_IRGRP S_IWGRP S_IXGRP

S_IRWXO S_IROTH S_IWOTH S_IXOTH

Мюьтексы POSIX

int pthread_mutex_init (

pthread_mutex_t *pMutex,

const pthread_mutexattr_t *pcAttr); //Указатель на аттрибуты

значения параметра функции pthread_mutexattr_setpshared()

nPShared

PTHREAD_PROCESS_PRIVATE

PTHREAD_PROCESS_SHARED

int pthread_mutexattr_init( pthread_mutexattr_t *pAttr);

int pthread_mutexattr_destroy(pthread_mutexattr_t *pAttr);

#ifdef _POSIX_THREAD_PROCESS_SHARED

int pthread_mutexattr_setpshared(pthread_mutexattr_t *pAttr,int nPShared); #endif

Разделяемая память POSIX

Сущ-ют средства, которые позволяют процессам обмениваться данными. Запрашиваем память, подключаемся в адресное пространство процесса, начиная с нек. адреса. Мб видна другим процессам.

POSIX shmget()

#include <sys/types.h>

#include <sys/shm.h>

int shmget(key_t nKey, //Ключ, опред. ID, номер участка

int nSize, int nShmFlg);

Предназначениа для создания дескриптора области памяти. Параметры аналогичны:

возможные значения флагов параметров функции shmget()

nKey IPC_PRIVATE

nShmFlg IPC_CREAT IPC_EXCL

младшие 9 бит – флаги, которые задают права доступа на разделяемую память

Создает объект и возвращает дескриптор

#include <sys/types.h>

#include <sys/shm.h>

void *shmat (//-at – attach, подключение данной области текущей памяти

int nShmId, //дескриптор области, то, что возвр. пред. функция

const void *pvShmAddr, //адрес в адресном пространстве процессов, NULL – ядро ОС самостоятельно находит адрес, чтобы подключить зад. обл. разделяемой памяти

int nShmFlg); //Флаг – поределяет способ

int shmdt(const void *pvShmAddr);

возможные значения флагов параметров функции shmat()

nShmFlg

SHM_RND (SHMLBA) – если указ-м конкретный адрес, то адрес будет выровнен

SHM_RDONLY – процесс только считывает, записывать не может

Пример

const key_t g_cKey = 1917;

// . . .

int nShmId = shmget(g_cKey,

sizeof (struct connect), //размер раздела памяти

IPC_CREAT | 0644); //флаг, пытается создать область памяти

if (nShmId < 0) //-1 если нет

{

perror("shmget"); //печатает такое сообщение в консоли

exit(1);

}

struct connect *pConnect = (struct connect *) shmat(nShmId, NULL, 0); //явное преобразование указателя // . . .

shmdt(pConnect); //отсоединяет от адр. пространства текущего процесса.

Проблема – ключ-идентификатор трудно выбрать

При помощи fork можно задавать параметры командной строки, перед. дочернему процессу.

Решение проблемы дублирования ключей

Варианты

- Использование в качестве ключа константы IPC_PRIVATE.

- Генерирование ключа при помощи функции ftok().

POSIX ftok()

#include <sys/types.h>

#include <sys/ipc.h>

key_t ftok(const char *pcszPathName, int nProjId);

По заданному файлу генерируем ключ. Пар-ры – (путь, номер проекта?)

stat() – функция для получения различных параметров. Вернет один ключ, даже если запускался в разл. процессах.

Разделяемая память Windows API

ANDLE WINAPI CreateFileMapping( //Создание объекта для работы с разд. памятью

__in HANDLE hFile,

__in_opt LPSECURITY_ATTRIBUTES lpAttributes, //NULL

__in DWORD dwProtect, //Способ доступа в памяти

__in DWORD dwMaximumSizeHigh,

__in DWORD dwMaximumSizeLow,

__in_opt LPCTSTR lpctszName );

возможные значения флагов параметров функции

dwProtect

PAGE_READONLY – исп. код из памяти и читать

PAGE_READWRITE

PAGE_WRITECOPY – режим копирования при записи

PAGE_EXECUTE_READ . . .

LPVOID WINAPI MapViewOfFile( //подсоединяет к адр. пространству процесса и возвр. указатель на ней

__in HANDLE hFileMappingObject,

__in DWORD dwDesiredAccess,

__in DWORD dwFileOffsetHigh, //смещение внутри обл. памяти, NULL – общая память

__in DWORD dwFileOffsetLow,

__in SIZE_T dwNumberOfBytesToMap //Размер );

BOOL WINAPI UnmapViewOfFile( //Передает адр. пр-во, отсоединяет.

__in LPCVOID lpcvBaseAddress );

dwDesiredAccess

FILE_MAP_READ

FILE_MAP_WRITE (и чтение тоже)

FILE_MAP_COPY

Каналы POSIX

нек. обл. памяти, в режиме очереди FIFO

POSIX pipe()

#include <unistd.h> // <io.h>

int pipe(int anFD[2]); // anFD[0] чтение, anFD[1] запись – указатель на массив из 2х дескрипторов

int dup2(int nOldFD, int nNewFD); //Дескриптор файла, новое значение. Закрывает файл, если нужно. Открывает 1, делает равным 1

ssize_t read(int nFD, void *pvBuf, size_t uCount); //то же, что и size_t но со значением nCount, если нет проблем

ssize_t write(int nFD, const void *pcvBuf, size_t uCount);

int eof(int nFD);

int close(int nFD); //Закрытие файла

Использование каналов в POSIX

Пример

$ ls j | more

Выводит содержимое текущего каталога, по умолчанию – список файлов | Считывает файл и выводит его постранично, если слишком большой

Реализация bash

1 pipe(anFD)

2 fork() (2 раза)

3 close(anFD[i]) (2 раза)

1 Создает канал для обмена, передает массив, создает директории 2 Создание процесса в POSIX В дочернем 0, в род. ID

Реализация ls

1 dup2(anFD[1], 1) //1 – вывод на консоль

2 close(anFD[i]) (2 раза)

3 execve("ls", argv, envp)

Тот же заполненный массив из двух дескрипторов, созд. новый дескриптор. То, что выводим на консоль, попадет в канал, 2й дескриптор продолжит существовать.

Реализация more

1 dup2(anFD[0], 0)

2 close(anFD[i]) (2 раза)

3 execve("more", argv, envp)

попадает в канал и читается другим процессом

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]