Навигация
Главная
Поиск
Форум
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
Реклама
Сейчас на сайте
Гостей: 8
На сайте нет зарегистрированных пользователей

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

Моделирование вычислительного центра на GPSS + Отчет + Блок схема
Моделирование работы перекрёстка по регулированию движения на GPSS + Поя...
Моделирование работы аэропорта на 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 Комментариев · 8920 Прочтений · Для печати

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


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



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

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

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

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

Пароль



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

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

Случайные загрузки
Microsoft SQL Ser...
C# в кратком изло...
AddPage [Исходник...
PHP в примерах
XPcontrol
Длинный заголовок...
Пример работы с б...
Ранги для форума
Удаление своего EXE
mp3tag
Assembler. Практикум
AUTOWEB
Delphi 2005 Учимс...
Система баннеро-о...
Ильдар Хабибуллин...
Х. М. Дейтел, П. ...
SUIPack
CoolHints2k v1.03
В.Понамарев - COM...
Tag Игра "Пятнашк...

Топ загрузок
Приложение Клие... 100774
Delphi 7 Enterp... 97833
Converter AMR<-... 20268
GPSS World Stud... 17014
Borland C++Buil... 14191
Borland Delphi ... 10291
Turbo Pascal fo... 7373
Калькулятор [Ис... 5984
Visual Studio 2... 5207
Microsoft SQL S... 3661
Случайные статьи
Игровые автоматы В...
Поток информации и...
Рассмотрим теперь ...
Для постоянных при...
Нарушения правильн...
Российский стандар...
Групповые функции
Для восстановления...
Разработка микропр...
Типовая структура ...
«Parimatch»: ставк...
Детская стоматолог...
Wap сайты - раскру...
Оператор поиска в ...
Методы save() и lo...
Определения риска
6.4. Работа с утв...
TRACE (НАЧАТЬ ТРАС...
Концепция с исполь...
Открытие документа
Разработать просто...
FairUse
Организация взаимо...
Обобщенное програм...
Производительность...
Статистика



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


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