Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 25
На сайте нет зарегистрированных пользователей

Пользователей: 13,372
новичок: vausoz
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Моделирование круглосуточного интернет кафе на GPSS + Отчет
База данных - словарь терминов на Delphi + Пояснительная записка
Моделирование работы класса персональных компьютеров на GPSS + Отчет + Б...

Использование разделяемой памяти в PHP
Источник: http://detail.phpclub.net/
Alexander Prohorenko

Перевод: Крушняков Кирилл
13.05.2004

IPC ("Inter-Process Communication" - межпроцессное взаимодействие) - одна из важнейших особенностей ОС семейства UNIX. Она позволяет различным процессам взаимодействовать между собой. В этой статье речь пойдёт о двух технологиях System V IPC (System V - одна из ключевых версий ОС UNIX компании AT&T - прим. пер.): о семафорах и разделяемой памяти. System V IPC впервые появилась в SVR2 (System V Release 2 - прим. пер.). System V IPC, однако, была реализована многими разработчиками. Она также доступна в SVR4.

Концепция IPC слагается из нескольких компонентов. Термин подразумевает различные механизмы обмена данными между процессами, стартовавшими в одной системе. IPC позволяет избежать создания огромного приложения с большим набором функций всех различных назначений и заменить его на использование отдельных, малых приложений, способных обмениваться данными между собой. Традиционный подход Unix заключается в том, чтобы позволить многопроцессорным системам запускать приложения в отдельных процессах (threads) для сокращения времени, требуемого на выполнение специфических задач.

На высоком уровне мы можем разделить межпроцессное взаимодействие на следующие наиболее крупные и важные разделы:
Сообщения: каналы (pipes) и очереди сообщений (pipes and message queues)
Разделяемая память (Shared memory)
Удаленный вызов процедур - RPC (remote procedure calls)
Синхронизация: семафоры и любые виды блокирования
Сетевое взаимодействие (API сокетов)

В этой статье речь идет о разделяемой памяти и синхронизации (семафорах). Детальное описание этих методов займет слишком много времени - существует огромное количество различного материала, посвященного этой теме. Если вы заинтересованы в подробном изучении, обратитесь ко множественным книгам по межпроцессному взаимодействию.
Идентификаторы IPC

Каждый объект IPC (очередь ли сообщений, семафор, или сегмент разделяемой памяти) обладает уникальным идентификатором (Id), который позволяет ядру ОС идентифицировать этот объект. К примеру, для того, чтобы сослаться на определенный сегмент разделяемой памяти, вам всего лишь необходимо знать уникальный идентификатор, назначенный этому сегменту.

Учтите, что идентификатор объекта IPC является уникальным только для одного типа объектов. Другими словами, только одна очередь сообщений может иметь идентификатор 12345, хотя номер 12345 может также использоваться семафорами и/или сегментами разделенной памяти.
Ключи IPC

Как создается идентификатор IPC? Для этого необходим ключ. Первым шагом при создании среды взаимодействия между приложениями является координирование использования ключей. Представьте себе это так: для того, чтобы позвонить кому-либо, вы должны знать его телефонный номер. Телефонная компания должна знать, как переслать ваш звонок абоненту. И только, когда он отвечает, происходит соединение.

В случае применения System V IPC "телефон" соединяет объекты одного типа. Телефонной компанией или способом маршрутизации является "ключ" IPC.

Приложения должны генерировать свои собственные ключи. Функция ftok() делает это и для клиента и для сервера. Значение ключа, возвращаемое функцией ftok(), зависит от значения inode и младшего значения идентификатора устройства для первого аргумента - файла - и символа - второго аргумента. Это не обеспечивает уникальности, но приложения могут проводить проверки на предмет коллизий и генерировать новые ключи по мере необходимости.
key_t mykey;
mykey = ftok ("/tmp/myapp", 'a');

В примере, приведенном выше, директория /tmp/myapp комбинируется с литеральным идентификатором a для генерации ключа. Другим распространенным примером является использование текущей директории:
key_t mykey;
mykey = ftok(".", 'a');

Обязанность проектирования алгоритма генерации ключей лежит на программисте прикладного приложения. Любой из этих методов должен учитывать конкурирующие состояния процессов и меры предотвращений "тупиковых" ситуаций. Для достижения наших демонстрационных целей мы ограничимся функцией ftok(). Если мы условимся, что каждый процесс-клиент будет запущен из собственного уникального домашнего каталога, то условие уникальности будет соблюдено полностью.

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

Команда ipcs отображает состояние всех объектов System V IPC.

ipcs -q: показывать только очереди сообщений
ipcs -s: показывать только семафоры
ipcs -m: показывать только разделяемую память
ipcs --help: для любознательных

По умолчанию показываются все три категории объектов. Рассмотрим пример простейшего вывода команды ipcs:
------ Shared Memory Segments --------
shmid owner perms bytes nattch status
------ Semaphore Arrays --------
^semid owner perms nsems status
------ Message Queues --------
msqid owner perms used-bytes messages
0 root 660 5 1

Мы видим единственную очередь сообщений с идентификатором 0. Она принадлежит пользователю root и обладает правами доступа 660, или -rw-rw---. Очередь содержит одно 5-ти байтовое сообщение.

Команда ipcs является мощным механизмом для мониторинга памяти ядра объектов IPC.
Команда ipcrm.

ipcrm удаляет объекты IPC из ядра. Однако, поскольку объекты IPC могут быть удалены с помощью системных вызовов из прикладной программы, необходимость удалять их вручную возникает редко. Команда очень простая:
ipcrm - type (тип) id (номер)

Необходимо обозначить тип удаляемого объекта параметром. Обратитесь за подробностями к справке man. Идентификатор IPC можно определить с помощью команды ipcs. Помните, что идентификатор уникален только для объектов одного типа. Вот почему необходимо указывать тип объекта при его удалении.
Семафоры.

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

Этот механизм также обеспечивает функции для работы с разделяемой памятью System V. Разделяемая память обеспечивает доступ к глобальным переменным для различных процессов. Демоны httpd и даже другие программы (на Perl, C и других языках) могут получить доступ к этим данным с целью глобального обмена данными. Помните, однако, что разделяемая память не защищена от одновременного доступа.

Таблица 1 демонстрирует переменные Unix, которые определяют параметры ограничений разделяемой памяти. Каждый подвид Unix обладает своей документацией по этим переменным. К примеру, во FreeBSD они являются частью конфигурации ядра. Вам потребуется перекомпилировать ядро для принятия изменений.

Table 1. Переменные разделяемой памяти UnixSHMMAX Максимальное количество разделяемой памяти, обычно 131072 байт
SHMMIN Минимальное количество разделяемой памяти, обычно 1 байт
SHMMNI Максимальное количество сегментов разделяемой памяти в системе, обычно 100
SHMSEG Максимальное количество сегментов разделяемой памяти для одного процесса, обычно 6


Функции сообщений могут посылать сообщения одним процессам и принимать сообщения от других. Они являются простым и эффективным способом обмена данными между процессами без необходимости использования системы сокетов Unix.
Использование разделяемой памяти и семафоров

Изучая что-то новое, каждый разработчик хочет начать использовать эту технологию на практике, хотя бы написав простую программу "Hello, world!". Это нормально, поэтому приведем минимальные сведения, необходимые для того, чтобы вы могли создать этот простой тестовый пример.

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

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

Теперь возникает вопрос, как использовать семафор. На самом деле это весьма просто и понятно из приведенного примера кода. Единственная тонкость заключается в том, что, поскольку семафоры могут блокировать и разблокировать ресурсы, они также могут блокировать друг друга. Без аккуратного проектирования процессы могут попытаться овладеть одним и тем же семафором одновременно, вызывая долгие задержки при ожидании доступа. И, даже при должном проектировании, всегда будет верхний предел производительности в мультипроцессорных системах. За подробностями обратитесь к любой книге, посвященной многопроцессорным системам.

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

int sem_get (int key [, int max_acquire [, int perm]])

Эта функция возвращает id семафора. Он будет положительным в случае успеха и равен FALSE в случае ошибки. Используйте id для доступа к семафору V с помощью ключа key.

Если это необходимо, семафор может обладать правами доступа, указанными в параметре perm. Значение по умолчанию: 0666. Параметр max_acquire управляет количеством процессов, которые могут одновременно получить доступ к семафору. По умолчанию он равен 1.

Вторичный вызов функции sem_get() для того же ключа вернет другой id, но они оба будут указывать на один и тот же семафор.

bool sem_acquire(int sem_identifier)

Эта функция возвращает TRUE в случае успеха и FALSE при неудаче. Она заблокируется, если необходимо, до тех пор, пока не займет запрошенный семафор. Процесс попытки занять запрошенный семафор будет длиться бесконечно, если он превысит значение параметра max_acquire.

Все семафоры, используемые в процессе, но не освобожденные явно, будут закрыты автоматически. Однако, это породит предупреждение.

int shm_attach(int key [, int memsize [, int perm]])

Эта функция создает или открывает сегмент разделяемой памяти. shm_attach() возвращает идентификатор для использования при получении доступа к сегменту с помощью заданного ключа. Размер сегмента в байтах будет равен mem_size. Значение по умолчанию равно sysvshm. init_mem в файле конфигурации PHP (или 10,000 байт, если оно не установлено в файле). Необязательный параметр perm определяет права доступа и равен 0666 по умолчанию.

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

mixed shm_get_var(int id, int variable_key)

Эта функция возвращает переменную, идентифицируемую параметром variable_key, из сегмента разделяемой памяти с идентификатором id. Переменная остается в разделяемой памяти.

int shm_put_var(int shm_identifier, int variable_key, mixed variable)

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

bool sem_release(int sem_identifier)

Эта функция освобождает семафор, если он занят текущим процессом. В противном случае выдает предупреждение (warning). Возвращает TRUE в случае успеха и FALSE в случае ошибки.

После освобождения семафора для того, чтобы его повторно использовать, вызовите sem_acquire().

int shm_remove(int shm_identifier)

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

bool sem_remove(int sem_identifier)

Эта функция удаляет семафор, заданный с помощью sem_identifier, если он был создан с помощью sem_get. Возвращает TRUE в случае успеха и FALSE в случае ошибки. Если семафора с указанным идентификатором не существует, она породит предупреждение (warning). После удаления семафор недоступен.
Образец кода, использующего разделяемую память

Вот образец кода, использующего разделяемую память, с попутными комментариями:
MEMSIZE = 512; // объём выделяемой разделяемой памяти
$SEMKEY = 1; // ключ семафора
$SHMKEY = 2; // ключ разделяемой памяти

echo "Старт.\n";

// Создаем семафор
$sem_id = sem_get($SEMKEY, 1);
if ($sem_id === false)
{
echo "Ошибка при создании семафора";
exit;
}
else
echo "Создан семафор $sem_id.\n";

// Занимаем семафор
if (! sem_acquire($sem_id))
{
echo "Ошибка при попытке занять семафор $sem_id.\n";
sem_remove($sem_id);
exit;
}
else
echo "Успешно занят семафор $sem_id.\n";

// Подключаем разделяемую память
$shm_id = shm_attach($SHMKEY, $MEMSIZE);
if ($shm_id === false)
{
echo "Ошибка при подключении разделяемой памяти.\n";
sem_remove($sem_id);
exit;
}
else
echo "Успешное подключение разделяемой памяти: $shm_id.\n";

// Пишем переменную 1
if (!shm_put_var($shm_id, 1, "Переменная 1"))
{
echo "Ошибка при попытке записать переменную 1 в разделяемую память $shm_id.\n";

// Овобождаем ресурсы.
sem_remove($sem_id);
shm_remove($shm_id);
exit;
}
else
echo "Переменная 1 записана в разделяемую память.\n";

// Пишем переменную 2
if (!shm_put_var($shm_id, 2, "Переменная 2"))
{
echo "Ошибка при попытке записать переменную 2 в разделяемую память $shm_id.\n";

// Освобождаем ресурсы.
sem_remove($sem_id);
shm_remove ($shm_id);
exit;
}
else
echo "Переменная 2 записана в разделяемую память.\n";

// Читаем переменную 1
$var1 = shm_get_var($shm_id, 1);
if ($var1 === false)
{
echo "Ошибка при попытке прочитать переменную 1 из разделяемой памяти $shm_id, " .
"возвращенное значение=$var1.\n";
}
else
echo "Прочитана переменная 1=$var1.\n";

// Читаем переменную 2
$var2 = shm_get_var ($shm_id, 2);
if ($var1 === false)
{
echo "Ошибка при попытке прочитать переменную 2 из разделяемой памяти $shm_id, " .
"возвращенное значение=$var2.\n";
}
else
echo "Прочитана переменная 2=$var2.\n";

// Освобождаем семафор
if (!sem_release($sem_id))
echo "Ошибка при попытке освободить семафор $sem_id.\n";
else
echo "Семафор $sem_id освобожден.\n";

// Удаляем сегмент разделяемой памяти
if (shm_remove ($shm_id))
echo "Сегмент разделяемой памяти успешно удален.\n";
else
echo "Ошибка при попытке удалить сегмент разделяемой памяти $shm_id.\n";

// Удаляем семафор.
if (sem_remove($sem_id))
echo "Семафор успешно удален.\n";
else
echo "Ошибка при попытке удалить семафор $sem_id.\n";

echo "Конец.\n";

?>

Вот пример кода, выполняющего различные операции с разделяемой памятью:
// Создаем блок разделяемой памяти размером 100 байт и с идентификатором равным 0xff3
$shm_id = shmop_open(0xff3, "c", 0644, 100);

if(!$shm_id)
{
echo "Ошибка при создании сегмента разделяемой памяти.\n";
}

// Получаем размер сегмента разделяемой памяти
$shm_size = shmop_size($shm_id);
echo "Блок разделяемой памяти с размером: ". $shm_size . " создан.\n";

// Пишем тестовую строку в сегмент разделяемой памяти
$shm_bytes_written = shmop_write($shm_id, "Мой блок разделяемой памяти", 0);

if($shm_bytes_written != strlen("Мой блок разделяемой памяти"))
{
echo "Ошибка при попытке записать данные полностью\n";
}

// Считываем записанную строку
$my_string = shmop_read($shm_id, 0, $shm_size);

if(!$my_string)
{
echo "Ошибка при попытке чтения разделяемой памяти\n";
}

echo "Данные в разделяемой памяти равны: ".$my_string."\n";

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

if(!shmop_delete($shm_id))
{
echo "Ошибка при попытке пометить блок разделяемой памяти на удаление.";
}

shmop_close($shm_id);

?>
Опубликовал Kest November 05 2008 21:35:28 · 0 Комментариев · 8931 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
Delphi Быстрый Ст...
Abbrevia
Cтатьи Королевств...
Ehlib
IIIDTrans
Domen Name IP
Дарахвелидзе П., ...
Midi
Система баннеро-о...
Adapter (пример D...
JanComp
Электронный магаз...
C++ Builder в за...
DeleteEdit
Удаление своего EXE
Измерение тактово...
AlnComponents
Библия хакера 2 К...
Animated Menus
WinPopup

Топ загрузок
Приложение Клие... 100774
Delphi 7 Enterp... 97839
Converter AMR<-... 20268
GPSS World Stud... 17014
Borland C++Buil... 14193
Borland Delphi ... 10293
Turbo Pascal fo... 7374
Калькулятор [Ис... 5984
Visual Studio 2... 5207
Microsoft SQL S... 3661
Случайные статьи
Найти всю информац...
Виртуальные машины...
Архитектура ОП дол...
CGI+SSI - пример с...
Процедура SetTextS...
Как заработать на ...
Проходящая через и...
Модели выполнения ...
Четкое разграничен...
Глава 26. ХР в ...
Изменение таблиц и...
Хотя параметры без...
Формы представлени...
Реальные стандарты...
Служба удаленного ...
Приемы проверочных...
Генерация контента...
2. Приведенные ниж...
Кредит в банке под...
Подсчет времени ра...
Правила определени...
Windows Server vNe...
Переключатель Micr...
Трудности при испо...
Неудержимый Рост К...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?