Мегаобучалка Главная | О нас | Обратная связь


ЭКЗАМЕНАЦИОННЫЙ БИЛЕТ № 6. 1. Совместное использование объектов ядра несколькими процессами



2016-01-02 494 Обсуждений (0)
ЭКЗАМЕНАЦИОННЫЙ БИЛЕТ № 6. 1. Совместное использование объектов ядра несколькими процессами 0.00 из 5.00 0 оценок




1. Совместное использование объектов ядра несколькими процессами.

HANDLE CreateWaitableTimer(

PSLCURITY_ATTRIBUTES psa,

BOOL bManualReset,

PCTSTR pszName);

 

HANDLE CreateFileMapping(

HANDLE hFile,

PSECURITY_ATTRIBUTES psa,

DWORD flProtect,

DWORD dwMaximumSizeHigh,

DWORD dwMaximumSizeLow,

PCTSTR pszName);

 

HANDLE CreateJobObject(

PSECURITY_ATTRIBUTES psa,

PCTSTR pszName);

Последний параметр, pszName, у всех этих функций одинаков. Передавая в нем NULL можно создать безымянный (анонимный) объект ядра. В этом случае можно разделить объект между процессами. Чтобы разделять объект по имени, необходимо присвоить ему какое-нибудь имя. Тогда вместо NULL в параметре pszName нужно передать адрес строки с именем, завершаемой нулевым символом. Имя может быть длиной до MAX_PATH знаков (это значение определено как 260). К сожалению, Microsoft ничего не сообщает о правилах именования объектов ядра. Например, создавая объект с именем JeffObj, нет гарантии того, что в системе еще нет объекта ядра с таким именем. И что хуже, все эти объекты делят единое пространство имен. Из-за этого следующий вызов CreateSemaphore будет всегда возвращать NULL:

HANDLE hMutex = CreateMutex(NULL. FALSE, "JeffObj");

HANDLE hSem = CreateSemaphore(NULL, 1, 1, "JeffObj");

DWORD dwErrorCode = GetLastError();

После выполнения этого фрагмента значение dwErrorCode будет равно ERROR_INVALID_HANDLE.

Рассмотрим, как разделять их между процессами по именам. Допустим, после запуска процесса А вызывается функция:

HANDLE hMutexPronessA = CreateMutex( NULL,

FALSE,

"JeffMutex");

Этот вызов заставляет систему создать новый объект ядра "мъютекс" и присвоить ему имя JeffMutex. Описатель hMutexProcessA в процессе А не является наследуемым, — он и не должен быть таковым при простом именовании объектов.

Спустя какое-то время некий процесс порождает процесс В. Необязательно, чтобы последний был дочерним от процесса А; он может быть порожден Explorer или любым другим приложением. Когда процесс В приступает к работе, исполняется код:


HANDLE hMutexProcessB = CreateMutex( NULL,

FALSE,

"JeffMutex");

При этом вызове система сначала проверяет, не существует ли уже объект ядра с таким именем. Если да, то ядро проверяет тип этого объекта. Поскольку есть попытка создать мьютекс и его имя тоже JeffMutex, система проверяет права доступа вызывающего процесса к этому объекту. Если у него есть все права, в таблице описателей, принадлежащей процессу В, создается новая запись, указывающая на существующий объект ядра. Если же вызывающий процесс не имеет полных прав на доступ к объекту или если типы двух объектов с одинаковыми именами не совпадают, вызов CreateMutex заканчивается неудачно и возвращается NULL.

Однако, хотя процесс В успешно вызвал CreateMutex, новый объект-мьютекс он не создал. Вместо этого он получил свой описатель существующего объекта-мьютекса. Счетчик объекта, конечно же, увеличился на 1, и теперь этот объект не разрушится, пока его описатели не закроют оба процесса — А и В. Значения описателей объекта в обоих процессах скорее всего разные, но так и должно быть, каждый процесс будет оперировать с данным объектом ядра, используя свой описатель.

Вызывая CreateMutex, процесс В передает ей атрибуты защиты и второй параметр. Эти параметры игнорируются, если объект с указанным именем уже существует. Приложение может определить, что оно делает: создает новый объект ядра или просто открывает уже существующий, — вызвав GetLastError сразу же после вызова одной из Create-функций:

HANDLE hMutex = CreateMutex(&sa, FALSE, "JeffObj");

if (GetLastError() == ERROR_ALREADY_EXISTS)

{

// открыт описатель существующего объекта sa.lpSecurityDescriptor и второй параметр (FALSE) игнорируются

}

else

{

// создан совершенно новый объект sa.lpSecurityDescriptor и второй параметр (FALSE) используются при создании объекта

}

Есть и другой способ разделения объектов по именам. Вместо вызова Create-функции процесс может обратиться к одной из следующих Open-функций:

HANDLE OpenMutex(

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

 

HANDLE OpenEvent(

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

 

HANDLE OpenSemaphore(

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

 

HANDLE OpenWaitableTimer(

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

 

HANDLE OpenFileMapping(

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

 

HANDLE OpenJobObject(


 

DWORD dwDESIredAccess,

BOOL bInheritHandle,

PCTSTR pszName);

Все эти функции имеют один прототип. Последний параметр, pszName, определяет имя объекта ядра. В нем нельзя передать NULL — только адрес строки с нулевым символом в конце. Эти функции просматривают единое пространство имен объектов ядра, пытаясь найти совпадение. Если объекта ядра с указанным именем нет, функции возвращают NULL, a GetLastError — код 2 (ERROR_FILE_NOT_FOUND). Но если объект ядра с заданным именем существует и если его тип идентичен тому, что указан, система проверяет, разрешен ли к данному объекту доступ запрошенного вида (через параметр dwDesiredAccess). Если такой вид доступа разрешен, таблица описателей в вызывающем процессе обновляется, и счетчик числа пользователей объекта возрастает на 1. Если параметру bInheritHandle присвоено значение TRUE, то получится наследуемый описатель.

Главное отличие между вызовом Create- и Open-функций в том, что при отсутствии указанного объекта Create-функция создает его, а Open-функция просто уведомляет об ошибке.

 

 

2. Критические секции и защита данных.

Критические секции -- это объекты, используемые для блокировки доступа всех нитей (threads) приложения, кроме одной, к некоторым важным данным в один момент времени. Например, имеется переменная m_pObject и несколько нитей, вызывающих методы объекта, на который ссылается m_pObject, причем эта переменная может изменять свое значение время от времени. Иногда там даже оказывается нуль.

3. Анонимные каналы. Именованные каналы.

Анонимные каналы Win32 позволяют проводить одностороннее

(полудуплексное), символьно-ориентированное межпроцессное

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

дескриптор записи. Для создания канала служит следующая функция

CreatePipe:

BOOL CreatePipe ( PHANDLE phRead, PHANDLE phWrite,

LPSECURITY_ATTRIBUTES lpsa, DWORD cbPipe)

Чтобы использовать канал для IPC, нужен еще один процесс, с которым

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

Чтение из дескриптора чтения канала блокируется, если канал пуст. В

противном случае считывается столько байтов, сколько имеется в канале, но не

превышая количества, указанного при вызове ReadFile. Также блокируется

операция записи в заполненный канал, который реализуется в буфере памяти.

Кроме всего прочего, анонимные каналы пропускают данные только в одну

сторону. Для двунаправленной связи нужны два канала.

Именованные каналы

Именованные каналы обладают рядом особенностей, которые делают их

удобным средством реализации приложений с использованием IPC.

Особенности именованных каналов (некоторые из них присутствуют не всегда)

перечислены ниже.

• Именованные каналы ориентированы на сообщения, так что читающий

процесс может читать сообщения переменной длины точно так, как они

передаются записывающим процессом.

• Именованные каналы двунаправлены, так что два процесса могут

обмениваться сообщениями по одному и тому же каналу.

• Может быть несколько независимых экземпляров именованного канала.

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

используя один и тот же канал, и сервер может ответить клиенту по тому

же экземпляру канала.

• К каналу по имени могут обращаться системы в сети. Связь через

именованный канал не зависит от того, работают ли оба процесса на одной

машине или на разных.

• Существует несколько функций-полуфабрикатов, упрощающих

взаимодействие по именованному каналу и соединение клиента с сервером.

Использование именованных каналов

Функция CreateNamedPipe создает первый экземпляр именованного

канала и возвращает его дескриптор. Также эта функция определяет

максимальное количество экземпляров канала и, следовательно, количество

клиентов, которых можно обслуживать одновременно.

Обычно процесс создания называется сервером. Процессы-клиенты,

возможно, работающие на других системах, открывают этот канал с помощью

CreateFile.

Создание именованных каналов

Ниже приведена функция CreateNamedPipe.

HANDLE CreateNamedPipe ( LPCTSTR lpszPipeName,

DWQRD fdwOpenMode, DWORD fdwPipeMode,

DWORD nMaxInstances, DWORD cbOutBuf,

DWORD cblnBuf, DWORD dwTimeOut,

LPSECURITY_ATTRIBUTES lpsa)

Параметры

lpszPipeName обозначает имя канала в форме: \\.\pipe\[путь]имя-канала

Точка обозначает локальную машину; иначе говоря, создать канал на

удаленной машине нельзя.

fdwOpenMode имеет одно из следующих значений:

- PIPE_ACCESS_DUPLEX — эквивалентно комбинации GENERIC_READ

и GENERIC_WRITE;

- PIPE_ACCESS_INBOUND — направление данных только от клиента к

серверу, эквивалентно GENERIC_READ;

- PIPE_ACCESS_OUTBOUND — эквивалентно GENERIC_WRITE.

Режим также может быть FILE_FLAG_WRITE_THROUGH (не используется

для каналов сообщений) и FILE_FLAG_OVERLAPPED.

fdwPipeMode может принимать три взаимоисключающих пары флагов.

Они указывают, является ли запись ориентированной на сообщения или

байтовой, осуществляется ли чтение по сообщениям или по блокам и

блокируется ли операция чтения.

- PIPE_TYPE_BYTE и PIPE_TYPE_MESSAGE, которые взаимно исключают

друг друга, указывают, записываются ли данные в канал как поток байтов

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

тот же тип.

- PIPE_READMODE_BYTE и PIPE_READMODE_MESSAGE указывают,

читаются ли данные как поток байтов или как поток сообщений. Для

PIPE_READMODE_MESSAGE необходимо PIPE_TYPE_MESSAGE.

- PIPE_WAIT и PIPE_NOWAIT определяют, будет ли операция ReadFile

блокироваться. Указывайте значение PIPE_WAIT, поскольку для

асинхронного ввода-вывода есть способы получше.

nMaxInstances определяет количество экземпляров канала и,

следовательно, количество одновременно обслуживаемых клиентов. Если

указать значение PIPE_UNLIMITED_ INSTANCES, количество каналов будет

определять ОС в зависимости от доступных системных ресурсов.

cbOutBuf и cbInBuf задают размеры в байтах буферов ввода и вывода,

используемых для именованных каналов. Если указать нуль, будут

использоваться значения по умолчанию.

dwTimeOut — принятый по умолчанию тайм-аут (в миллисекундах) для

функции WaitNamedPipe. Эта ситуация, в которой функция создания

определяет тайм-аут для другой функции, является уникальной.

Возвращаемое значение в случае ошибки — INVALID_HANDLE_VALUE,

так как дескрипторы каналов подобны дескрипторам файлов.

lpsa играет ту же роль, что и в других функциях создания.

При первом вызове CreateNamedPipe фактически создается именованный

канал, а не просто экземпляр. При закрытии последнего дескриптора

экземпляра сам этот экземпляр удаляется. Удаление последнего экземпляра

именованного канала вызывает удаление самого канала.

Подключение клиента к именованному каналу

Клиент может подключиться к именованному каналу с помощью вызова

CreateFile с указанием имени канала. Во многих случаях клиент и сервер

находятся на одной машине; тогда имя имеет вид: \\.\pipe\[путь]имя_канала

Если бы сервер находился на другой машине, имя выглядело бы так:

\\имя_сервера\pipe\[путь]имя_канала

Если сервер локальный, то применение для имени символа "." вместо

указания имени самой машины значительно повышает быстродействие.

Функции состояния именованного канала

GetNamedPipeHandleState возвращает для данного открытого

дескриптора сведения о том, находится ли канал в блокируемом или

неблокируемом режиме, ориентирован ли он на сообщения или на байты, о

количестве экземпляров канала и т.д.

SetNamedPipeHandleState позволяет программе задавать эти атрибуты

состояния.

GetNamedPipelnfo определяет, связан ли дескриптор с клиентом или

сервером, каков размер буфера и т.д.

Функции подключения именованного канала

После создания экземпляра именованного канала сервер может отслеживать

подключение клиента (с помощью функций CreateFile или CallNamedPipe),

используя функцию ConnectNamedPipe.

BOOL ConnectNamedPipe ( HANDLE hNamedPipe,

LPOVERLAPPED lpo)

Если задать в lpo значение NULL, выполнение ConnectNamedPipe

завершится сразу же, как только появится подключение клиента. Обычно

функция возвращает TRUE. Значение FALSE может быть, если клиент

подключается между вызовами сервером функций CreateNamedPipe и

ConnectNamedPipe. В этом случае GetLastError возвращает значение

ERROR_PIPE_CONNECTED.

После возвращения из ConnectNamedPipe сервер может читать запросы с

помощью ReadFile и записывать ответы, используя WriteFile. В заключение

сервер должен вызвать функцию DisconnectNamedPipe, чтобы освободить

дескриптор (экземпляр канала) для соединения с другим клиентом.

Последняя функция, WaitNamedPipe, предназначена для синхронизации

подключений клиента. Эта функция завершается, если на сервере имеется

незавершенное обращение к ConnectNamedPipe. Используя

WaitNamedPipe, клиент может убедиться, что сервер готов к подключению,

после чего вызвать CreateFile. Кроме того, вызов сервером функции

ConnectNamedPipe в этом случае завершится успешно.

Соединение клиента и сервера через именованный канал

Сначала в последовательности сервера осуществляется подключение

клиента, с которым сервер связывается до тех пор, пока тот не разорвет

соединение, затем сервер закрывает подключение на стороне сервера и

соединяется с другим клиентом.

Далее приводится последовательность подключения клиента, в которой

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

соединиться через тот же экземпляр именованного канала. Клиент может

соединяться с сервером через сеть, если ему известно имя сервера.

Обратите внимание, что между клиентом и сервером происходит состязание.

Во-первых, вызов клиентом WaitNamedPipe завершится неудачно, если

сервер еще не создал именованный канал. Во-вторых, возможны

обстоятельства, в которых клиент может завершить свой вызов CreateFile

прежде, чем сервер вызовет ConnectNamedPipe. В этом случае

ConnectNamedPipe возвратит FALSE, но связь через именованный канал

будет работать, как положено.

Транзакционные функции именованного канала

Клиент выполняет следующее:

• открывает экземпляр канала, создавая долговременное подключение к

серверу и потребляя этот экземпляр канала;

• попеременно посылает запросы и ожидает ответов;

• закрывает подключение.

Обычную последовательность функций WriteFile, ReadFile можно

считать отдельной транзакцией клиента, и в Win32 имеется такая функция для

каналов сообщений.

BOOL TransactNamedPipe ( HANDLE hNamedPipe,

LPVOID lpvWriteBuf, DWORD cbWriteBuf,

LPVOID lpvReadBuf, DWORD cbReadBuf,

LPDWORD lpcbRead, LPOVERLAPPED lpa)

Назначение параметров не нуждается в объяснении, так как эта функция

представляет собой сочетание WriteFile и ReadFile для дескриптора

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

*lpcbRead задает длину сообщения.

Функция TransactNamedPipe удобна, но требует постоянного

подключения, что ограничивает число клиентов.

CallNamedPipe, вторая функция-полуфабрикат, лишена этого недостатка,

так как объединяет в себе всю последовательность: CreateFile, WriteFile,

ReadFile, CloseHandle.

Преимущество заключается в более эффективном использовании канала,

несмотря на издержки подключения при каждом запросе.

BOOL CallNamedPipe ( LPCPSTR lpszPipeName,

LPVOID lpvWriteBuf, DWORD сbWriteBuf,

LPVOID lpvReadBuf, DWORD сbReadBuf,

LPDWORD lpcbRead, DWORD dwTimeOut)

Использование параметров подобно TransactactNamedPipe с тем

исключением, что для канала указывается имя, а не дескриптор. Функция

CallNamedPipe является синхронной.

Здесь также указывается тайм-аут в миллисекундах — для подключения, но

не для транзакции. Для dwTimeOut существует также три специальных

значения:

• NMPWAIT_NOWAIT;

• NMPWAIT_WAIT_FOREVER;

• NMPWAIT_USE_DEFAULT_WAIT — в этом случае используется тайм-аут

по умолчанию, заданный при вызове CreateNamedPipe.

Наблюдение за сообщениями в именованном канале

Кроме чтения именованного канала с помощью ReadFile, можно также

определять, присутствует ли в нем сообщение, которое можно считать. Для

этого служит функция PeekNamedPipe.

BOOL PeekNamedPipe (HANDLE hPipe, LPVOID lpvBuffer,

DWORD cbBuffer, LPDWQRD lpcbRead,

LPDWORD lpcbAvail, LPDWORD lpcbMessage)

Функция PeekNamedPipe читает все байты или сообщения в канале, не

разрушая их; она не блокируется и завершается немедленно.

Чтобы узнать, есть ли данные в канале, проверьте значение *lpcbAvail;

если есть, *lpcbAvail будет больше нуля. В этом случае lpvBuffer и

lpcbRead могут иметь значение NULL. Е СЛИ буфер задан параметрами

lpvBuffer и cbBuffer, то *lpcbMessage сообщает, есть ли оставшиеся байты

сообщения, которые не вписываются в буфер, что позволяет выделить большой

буфер перед чтением из именованного канала. В байтовом режиме канала это

значение нулевое.

Еще раз подчеркнем, что PeekNamedPipe не уничтожает сообщения, так

что для удаления сообщений или байтов из канала нужен дополнительный

вызов ReadFile.

Безопасность именованного канала

Ниже приведены важные права безопасности для именованных каналов.

• GENERIC_READ.

• GENERIC_WRITE.

• SYNCHRONIZE (разрешает ожидание потока).

Соответствующие права устанавливаются в зависимости от режима доступа

(дуплексный, входящий или исходящий). Для всех трех режимов требуется

право SYNCHRONIZE.

 

 



2016-01-02 494 Обсуждений (0)
ЭКЗАМЕНАЦИОННЫЙ БИЛЕТ № 6. 1. Совместное использование объектов ядра несколькими процессами 0.00 из 5.00 0 оценок









Обсуждение в статье: ЭКЗАМЕНАЦИОННЫЙ БИЛЕТ № 6. 1. Совместное использование объектов ядра несколькими процессами

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Личность ребенка как объект и субъект в образовательной технологии: В настоящее время в России идет становление новой системы образования, ориентированного на вхождение...
Как построить свою речь (словесное оформление): При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою...
Почему люди поддаются рекламе?: Только не надо искать ответы в качестве или количестве рекламы...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (494)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.012 сек.)