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

27. Взаимодействие процессов/потоков, взаимное исключение, синхронизация (базовые сведения)

28. Реализация взаимного исключения. Механизм CriticalSection Win32. 29. Сихронизация при управлении процессами и потоками (создание, приостановка, завершение) 30. Функции ожидания Win32. Объекты ожидания: объекты файловой системы, объекты IPC (Event, Mutex, Semaphore, таймеры) 31. Использование каналов (pipe, named pipe) и почтовых ящиков (mailslot) для обмена данными. 32. Использование файловой системы для обмена данными.

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

Задачи взаимодействия

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

– общее управление задачами и потоками;

– обмен данными между ними;

– обеспечение их бесконфликтного согласованного взаимодействия.

Возникающие сложности вытекают из таких отличий многозадачных систем, в частности, Win 32, как:

– асинхронное выполнение отдельных задач (процессов) и потоков, причем механизм управления им скрыт, как правило, от прикладной программы;

– разделенные и изолированные адресные пространства отдельных задач (процессов), что исключает простой совместный доступ к элементам данных.

Примечание. Сказанное относится к большинству систем с истинной (вытесняющей) многозадачностью и, вообще говоря, может не быть верным для других.

Для того, чтобы система сохраняла управляемость, контроль за поведением задач и их взаимодействие осуществляется ее ядром, точнее, переключение задач выполняет планировщик, а за синхронизацию и обмен отвечают соответствующие модули межпроцессных интерфейсов. Прикладные программы могут лишь обращаться к системе с запросом того или иного управляющего действия. Напомним также, что в Win 32 "единицей" владения ресурсами является процесс, а единицей распределения процессорного времени – поток; упоминавшиеся выше нити (см. тему процессов и потоков) не вносят в данном случае существенной новизны.

Важнейшими проблемами при взаимодействии задач (процессов) и потоков в многозадачной системе асинхронность их выполнения и возможность одновременного доступа к объектам (ресурсам) при, в то же время, изоляции адресных пространств и, соответственно, множеств собственных объектов задач.

Примечание. Под объектом в данном случае имеется в виду любое образование, над которым программа ("субъект") выполняет какие-либо действия: элементы данных, структуры, файлы и т.д. К понятию объекта как концепции в объектном и объектно-ориентированном программировании это отношения не имеет.

Т.о., могут быть выделены следующие "проблемные" ситуации:

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

– один и тот же объект используется несколькими программами, но требуется устранить возможные "накладки" и некорректности одновременного (и заранее не предсказуемого) доступа.

В первом случае приходится говорить об обмене данными (объектами), во втором – об организации совместного использования этих данных. Более строго, выделяются следующие 3 основных задачи.

1. Межпроцессный обмен – передача информации (объектов данных) между процессами.

2. Задача синхронизации – определение моментов активизации отдельных задач, имея в виду обеспечение эффективного по ряду критериев функционирования как отдельных задач, так и системы в целом.

3. Задача исключения – предотвращение одновременного и, как следствие, некорректного использования ресурсов, для которых такое использование недопустимо.

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

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

Ниже рассматриваются в основном механизмы взаимодействия, предлагаемые Win 32 API.

Обмен данными между процессами.

Win32 API предоставляет богатый набор средств обмена данными. Составной частью Win32 API является Interprocess communications (IPC) – набор средств для организации обмена и разделения данных между процессами.

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

– принципиальная необходимость передачи управления или данных между составными частями приложения;

– локальное (в пределах одной машины) или сетевое взаимодействие;

– необходимость взаимодействовать с приложениями другой ОС (interoperable – интероперабельность);

– ручной (пользователем) или автоматический выбор участников взаимодействия;

– количество участников взаимодействия;

– использование унифицированных механизмов (типа вырезки/вставить из буфера обмена);

– требования к производительности (сложные механизмы могут требовать дополнительных "накладным расходов");

– использование оконного (Windows-based) или консольного типа приложения (некоторые механизмов работают только с оконными приложениями).

Существуют следующие способы разделения и передачи данных между процессами.

Отображение проецируемых файлов

Объект “проецируемый файл” может использоваться двумя и более процессами одновременно как глобальная разделяемая область данных, отображенная каждым из процессов на свое адресное пространство. Для получения требуемого результата разделяться должна одна и та же проекция файла, а не проекции одного файла.

Вместо именованного файла проецироваться может часть файла подкачки, в этом случае говорят об использовании разделяемой памяти (Shared memory).

Оба метода были рассмотрены выше.

Неименованные транспортеры (Anonymous Pipe)

Один из классических способов взаимодействия процессов, известный еще в UNIX. С помощью функции CreatePipe процесс создает два описателя: один для чтения, другой для записи. Эти описатели аналогичны описателям файлов в том смысле, что с ними можно работать файловыми функциями ReadFile и WriteFile. Если породить дочерний процесс так, чтобы он наследовал описатели, то можно использовать описатели транспортера для взаимодействия процессов. Можно предложить следующую схему взаимодействия:

Пример. Консольный вариант традиционной "первой программы".

/* Дочерний процесс */

#include <stdio.h>

#include <string.h>

int main( void )

{

char WorkString[80] ;

while( strcmp( WorkString, "end" ))

{

scanf( "%s", WorkString );

printf( "%s\n", WorkString ) ;

}

return 0 ;

}

/* Родительский процесс */

#include <windows.h>

#include <stdio.h>

#include <conio.h>

int main(void)

{

HANDLE hStandardInput ;

HANDLE hPipeInput ;

HANDLE hPipeOutput ;

PROCESS_INFORMATION pi ;

STARTUPINFO si ;

char WorkString[80] ;

DWORD NumberOfBytesWritten ;

ZeroMemory( &si, sizeof(si)) ;

si.cb = sizeof( si ) ;

hStandardInput = GetStdHandle( STD_INPUT_HANDLE ) ;

CreatePipe( &hPipeInput, &hPipeOutput, NULL, 0 ) ;

SetStdHandle( STD_INPUT_HANDLE, hPipeInput ) ;

CreateProcess(NULL,"Child",NULL,NULL,TRUE,

CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);

SetStdHandle( STD_INPUT_HANDLE, hStandardInput ) ;

CloseHandle( hPipeInput ) ;

while( strcmp( WorkString, "end\n" ))

{

scanf( "%s", WorkString ) ;

strcat( WorkString, "\n" ) ;

WriteFile(hPipeOutput,WorkString,strlen(WorkString),

&NumberOfBytesWritten,NULL);

}

return 0 ;

}

Именованные транспортеры (Named Pipes)

Аналогичны предыдущим за исключением того, что при создании транспортеру присваивается уникальное глобальное имя вида \\.\pipe\<pipename>. Процесс, породивший транспортер называется сервером. Процесс, который присоединяется к транспортеру, называется клиентом. Клиент может присоединяться к серверу, находящемуся на удаленном компьютере в сети. Для обслуживания одновременно нескольких клиентов обычно порождаются несколько потоков.

Именованный трубопровод создается функцией CreateNamedPipe, возвращающей описатель (тип HANDLE) созданного объекта. Для дальнейшего использования его необходимо открыть функцией CreateFile по данному ранее имени, либо применяя специфические функции работы с трубопроводами, например, ConnectNamedPipe или TransactNamedPipe. Созданный объект удаляется универсальной функцией CloseHandle.

Почтовые ящики (MailSlots)

Подобны именованным транспортерам, но предоставляют более простой однонаправленный интерфейс. Процесс-сервер может создать почтовый ящик и дать ему имя, глобальное в сети. Любой клиент может с помощью операций работы с файлами отправить данные в этот ящик. Сервер по мере необходимости читает переданные ему данные. Возможна также широковещательная передача информации клиентом всем серверам домена.

Почтовый ящик создается функцией CreateMailslot, причем используется имя вида \\.\mailslot\[<path>\]<slotname>, где собственно имя ящика может включать символы ‘\’, не имея соответствия в реальной структуре каталогов (т.н. псевдодиректории). Для доступа к ящику файловыми функциями его надо открыть функцией CreateFile с использованием следующих вариантов имени файла:

\\.\mailslot\<slot_name> – локальный ящик;

\\<computer_name>\mailslot\<slot_name> – удаленный ящик;

\\<domain_name>\mailslot\<slot_name> – используя доменное имя;

\\*\mailslot\<slot_name> – используя первичный (primary) домен системы.

В ящик, открытый через доменное имя, нельзя записывать более 400 байт в один прием.

Если ящик будет использоваться более чем одним процессом (владельцем), то CreateFile должен задавать флаг доступа FILE_SHARE_READ.

Созданный ящик существует до тех пор, пока существует процесс-владелец, либо пока владелец или его потомок не удалят его описатель вызовом CLOSE_HANDLE.

Сокеты (Socket).

Существующий практически во всех сетевых ОС механизм межпроцессного взаимодействия в локальных системах и в сети, предусмотренных моделью взаимодействия открытых систем (OSI). Для идентификации участника взаимодействия используются пара параметров: сетевое имя или адрес машины плюс номер порта. Адреса записываются в соответствии с требованиями одного из семейств адресов (addresses family), например, IP-адреса­ции. Таким образом, сокеты являются программной надстройкой на унифицированном сетевом интерфейсе портов сеансового уровня модели OSI..

Сокеты обеспечивают решение практически всех задач межпроцессного (межпрограммного) взаимодействия независимо от физического размещения программ:

– взаимное обнаружение и идентификация;

– синхронизация;

– передача данных без установления соединения (пакетная, датаграммная);

– передача с установлением соединения (потоковая, виртуальный канал).

В Win 32 сокет является системным объектом, доступным посредством его описателя, тип данных SOCKET, совместим с HANDLE. Предоставляется ряд функций API для работы с ними.

socket – создание сокета. Задаются семейство адресов, тип сокета и протокол.

closesocket – закрытие сокета (действие системного объекта прекращается функцией CloseHandle).

bind – связывание сокета с ресурсом системы.

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

accept – подтверждение соединения.

send – посылка через сокет с установленным соединением.

sendto – посылка с явным указанием адресата. Предварительное установление соединения не требуется.

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

recvfrom – прием из сокета с явным указанием корреспондента. Предварительное установление соединения не требуется.

ioctlsocket – управление сокетом

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

Пока что доп. информацию см. в MSDN и курсах "ОСиС", "ВСиС".

Использование сообщения WM_COPYDATA

Структура COPYDATASTRUCT: dwData (просто int), cbData (размер), lpData (буфер этого размера). Передача сообщения обязательно по Send, а не Post.

Буфер обмена (Clipboard).

Широко применяемый в Windows механизм обмена информацией с использованием специального системного глобального буфера. При этом реализуется модель cut-copy-paste. Любое приложение может поместить данные в буфер обмена и получить данные из него.

BOOL OpenClipboard(hWndNewOwner)

BOOL CloseClipboard(void)

HANDLE GetClipboardData(uFormat)

HANDLE SetClipboardData(uFormat,hMem)

BOOL EmptyClipboard(void)

UINT EnumClipboardFormats(uPrevFormat)

int CountClipboardsFormats(void)

UINT RegisterClipboardFormat(lpszFormatName)

GetClipboardFormatName(uFormat, lpFormatName, int nMaxCount)

Динамический обмен данными (DDE)

Механизм DDE (Dynamic Data Exchange), ...

OLE – Присоединение и внедрение объектов

Механизм (протокол) OLE (Object Linking and Embedding) был первоначально предназначен для создания составных документов. С его помощью можно, например, вставить таблицу MS Excel в документ MS Word. При этом возможно как вставить таблицу целиком (embedding), так и вставить только ссылку на эту таблицу (linking). В дальнейшем возник также OLE Automation, служащий для управления приложением из другого приложения. В настоящее время протокол OLE развился до набора технологий, лежащих в основе построения современных информационных систем, например, ActiveX.

Использование динамически компонуемых библиотек

Если два или более приложений используют одну библиотеку DLL (dynamic link library, см. ниже), то они разделяют все глобальные переменные этой библиотеки. Глобальные переменные, как и вся библиотека, отображаются на адресные пространства разных процессов. Этот метод не привносит никакой новой функциональности по сравнению с отображением проецируемых файлов. Более того, при этом нарушается идеология "скрытия" данных.

Объявление переменных в DLL как shared либо private. По умолчанию обычно все переменные private.

Удаленный вызов процедур

Механизм RPC (Remote Procedure Call) является естественным развитием идеологии процедурного программирования. В рамках его подпрограмма рассматривается как черный ящик с документированными параметрами. Естественно попытаться сделать возможным исполнение этой процедуры на удаленном компьютере. Механизм осуществления этой идеи напоминает использование динамических библиотек: с приложением компонуется не сама процедура, а лишь некоторая заглушка, которая передает по сети параметры процедуры и принимает результат вычислений. У приложения создается иллюзия работы с локальной процедурой. Возможно исполнение процедуры и вызывающей программы под управлением разных операционных систем.

Клиент-сервер. На стороне клиента – заглушка (stub) с соответствующим именем. Задача заглушки клиента – упаковать аргументы и передать на сервера. На стороне сервера – тоже заглушка (server stub), она же прокси (proxy). Прокси распаковывает аргументы и вызывает нужную серверную функцию.

Как разновидность RPC – очередь сообщений MSMQ. Позволяет осуществлять вызов off-line.

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