|
Обновите ArcaOS до уровня NeoWPS
- Установите набор PNG иконок, нарисованных дизайнером, специализирующемся на оформлении OS/2
- Установите eSchemes 2018, чтобы менять цвета и кнопки на рабочем столе
|
Взаимодействие между процессами |
TITLE: Взаимодействие между процессами
DATE: 2012-08-11 17:56:09
AUTHOR: Capricorn
Введение
Любой программист, который пишет софт для многозадачной OS (а в наши дни других фактически не существует) рано или поздно сталкивается с необходимостью обеспечить взаимодействие между несколькими программами, которые должны работать в связке. В OS/2 для этой цели существует несколько механизмов: семафоры, пайпы, общая (разделяемая) память, очереди. Если с первыми двумя всё более-менее понятно и программисты активно используют их, то очереди и общая память почему-то обделены вниманием. На мой взгляд, совершенно незаслуженно. Цель данной статьи - подробно рассмотреть данные механизмы и дать рекомендации по их использованию. Но сначала, рассмотрим первые два.
Семафоры
Семафоры служат одной цели: синхронизации процессов. У семафора всегда есть 2 состояния: "занят" и "свободен". Суть синхронизации состоит в том, что соответствующая команда ожидания проверяет, занят ли семафор, и если да, замораживает Всего существует 2 вида семафоров: ивэнты и мутексы.
а) Семафор типа "event" ("событие") нужен для того, чтобы позволить одному треду дождаться, пока другой тред выполнит некоторую задачу.
Пример:
/*************/
/* */
/* Процесс 1 */
/* */
/*************/
#define INCL_DOS
#include
PSZ szSemName = "\\SEM32\\EVENT"; /* Имя семафора. Должно иметь префикс \SEM32\ */
HEV hevEvent1 = 0; /* Дескриптор семафора */
if (DosCreateEventSem(szSemName, /* Имя создаваемого семафора */
&hevEvent1, /* Сюда будет возвращён дескриптор семафора */
DC_SEM_SHARED, /* Разделяемый семафор */
FALSE)) /* Создаём семафор в сброшенном (занятом) состоянии */
return 1; /* Семафор создать не удалось */
/* Тут что-то делаем
До этого момента другой тред будет ждать
срабатывания (освобождения) семафора */
DosPostEventSem(hevEvent); /* Командуем семафору сработать (освободиться) */
/* Продолжаем работу */
DosCloseEventSem(hevEvent1); /* Избавляемся от семафора */
/*************/
/* */
/* Процесс 2 */
/* */
/*************/
Трубы (pipes)
[дополнение]
Разделяемая память
[дополнение]
Очереди
Ещё один способ взаимодействия между процессами - очереди (queues). Как уже говорилось ранее, очереди почему-то обойдены вниманием в пользу труб (pipes). На мой взгляд, совершенно незаслуженно. Очень часто очереди оказываются намного удобнее. Но, всё по-порядку.
Итак, очередь представляет собой механизм обмена сообщениями. Они чем-то напоминают очереди сообщений Presentation Manager'а, но есть существенные различия, поэтому не стоит их путать. Главное различие состоит в том, что не смотря на название, очереди могут работать не только в режиме собственно, очередей (FIFO), но и в режиме стека (LIFO), а также, по приоритетам.
Очереди всегда именованные.
Чаще всего, один процесс (тред), который мы условно назовём сервером, создаёт очередь и слушает его, другие (назовём их клиентами), открывают её и пишут туда сообщения. Разумеется, для прослушивани очереди логично организовать цикл.
Пример:
/**********************/
/* */
/* Процесс 1 (сервер) */
/* */
/**********************/
#define INCL_DOS
#include
#define QUEUE_FIFO 0 // Очередь
#define QUEUE_LIFO 1 // Стек
#define QUEUE_PRIO 2 // По приоритетам
#define MSG_QUIT 0x0001 /* Идентификатор сообщения для завершения цикла */
#define QUEUE_NAME "\\QUEUES\\special.que" /* Имя очереди.
* Должно иметь префикс \QUEUES\
*/
/* Функция, которая будет обрабатывать сообщения */
BOOL processMessage(ULONG ulMessageId, ULONG ulDataSize, PVOID pvData);
int main(void)
{
HQUEUE hQueue; /* Сюда будет помещён хэндл очереди */
APIRET rc; /* Результат вызова функций API */
/* Открываем очередь */
rc = DosCreateQueue(&hQueue, QUEUE_FIFO, QUE_NAME);
if (rc)
return rc;
/* Цикл обработки сообщений из очереди */
while(TRUE)
{
REQUESTDATA requestData; /* Структура для помещения данных запроса */
ULONG ulDataSize; /* Сюда будет помещён объём присланных данных */
PVOID pvData; /* Сюда будет помещена ссылка на присланные данные */
rc = DosReadQueue(hQueue, /* Хэндл очереди */
&requestData, /* Данные запроса */
&ulDataSize, /* Объём присланных данных */
&pvData, /* Присланные данные */
0, /* Читаем первый элемент из очереди */
FALSE, /* Ждём */
0, /* Приоритет не нужен */
NULLHANDLE); /* Нэндл семафора-собатия не нужен */
if (rc || requestData.ulData==MSG_QUIT)
break;
processMessage(ulMessageId, ulDataSize, pvData);
}
rc = DosCloseQueue(hQueue); /* Удаляем очередь */
return rc;
}
/**********************/
/* */
/* Процесс 2 (клиент) */
/* */
/**********************/
#define MSG_QUIT 0x0001 /* Идентификатор сообщения для завершения цикла */
#define QUEUE_NAME "\\QUEUES\\special.que" /* Имя очереди.
* Должно иметь префикс \QUEUES\
#define INCL_DOS
#include
int main(void)
{
HQUEUE hQueue; /* Сюда будет помещён хэндл очереди */
APIRET rc; /* Результат вызова функций API */
PID pid; /* Идентификатор процесса, создавшего очередь */
/* Открываем очередь */
rc = DosOpenQueue(&pid, &hQueue, QUE_NAME);
if (rc)
return rc;
rc = DosWriteQueue(hQueue, MSG_QUIT, 0L, NULL, 0L); /* Записываем в очередь сообщение*/
rc = DosCloseQueue(hQueue); /* Закрываем очередь */
return rc;
}
В данном примере мы первый процесс создаёт и слушает очередь. Другой процесс открывает очередь и записывает туда определённое нами сообщение о завершении работы (MSG_QUIT). Первый процесс, получив это сообщение, завершает свою работу.
Обратите внимание, что функция DosCloseQueue() по сути, удаляет хэндл очереди. Как только все хэндлы очереди будут удалены, удалится и сама очередь.
Так в чём же преимущество очередей перед трубами? Дело в том, что при использовании труб мы фактически имеем дело с непрерывным потоком данных. Это удобно, когда необходимо постоянно передавать большие объёмы данных. Но такие случаи очень редки. Чаще бывает нужно, чтобы один процесс сообщал другому о неких событиях или передавал какие-то команды, на которые другой процесс должен реагировать. В данном случае очереди гораздо удобнее, т. к. сообщение, помещённое в очередь как раз и является такой командой.
Комментарии: Прокомментируйте эту статью (напоминаем, автор работал над текстом несколько недель, уважайте мнение других).
|
В eComStation 2.0 реализовано удобное (автоматическое) переключение между WiFi и Ethernet-соединением. Что нового в eCS 2.0? |
|
|
|
Готовая eComStation на SSD диске
Последний активный опрос: Какая высота барьера RPM?
[Google]
|
IBM OS/2 Warp
|