Ідентифікатори IPC, Система, PHP, статті

Кожен об'єкт 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. Змінні розділяється пам'яті Unix
















SHMMAX Максимальна кількість розділяється пам'яті, звичайно 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 "Старт.
";

/ / Створюємо семафор
$sem_id = sem_get($SEMKEY, 1);
if ($sem_id === false)
{
    echo "Помилка при створенні семафора";
    exit;
}
else
    echo "Створено семафор $ sem_id.
";

/ / Займаємо семафор
if (! sem_acquire($sem_id))
{
    echo "Помилка при спробі зайняти семафор $ sem_id.
";
    sem_remove($sem_id);
    exit;
}
else
    echo "Успішно зайнятий семафор $ sem_id.
";

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

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

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

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

    / / Звільняємо ресурси.
    sem_remove($sem_id);
    shm_remove ($shm_id);
    exit;
}
else
    echo "Змінна 2 записана в поділювану пам'ять.
";

/ / Читаємо змінних 1
$var1 = shm_get_var($shm_id, 1);
if ($var1 === false)
{
    echo "Помилка при спробі прочитати змінну 1 з розділяється пам'яті $ shm_id," .
         "Повернене значення = $ var1.
";
}
else
    echo "Прочитана мінлива 1 = $ var1.
";

/ / Читаємо змінна 2
$var2 = shm_get_var ($shm_id, 2);
if ($var1 === false)
{
     echo "Помилка при спробі прочитати змінну 2 з розділяється пам'яті $ shm_id," .
          "Повернене значення = $ var2.
";
}
else
    echo "Прочитана мінлива 2 = $ var2.
";

/ / Звільняємо семафор
if (!sem_release($sem_id))
    echo "Помилка при спробі звільнити семафор $ sem_id.
";
else
    echo "Семафор $ sem_id звільнений.
";

/ / Видаляємо сегмент розділяється пам'яті
if (shm_remove ($shm_id))
    echo "Сегмент пам'яті, що розділяється успішно видалений.
";
else
    echo "Помилка при спробі видалити сегмент розділяється пам'яті $ shm_id.
";

/ / Видаляємо семафор.
if (sem_remove($sem_id))
    echo "Семафор успішно видалений.
";
else
    echo "Помилка при спробі видалити семафор $ sem_id.
";

echo "Кінець.
";

?>


Ось приклад коду, що виконує різні операції з пам'яттю:

<?php
/ / Створюємо блок розділяється пам'яті розміром 100 байт і з ідентифікатором рівним 0xff3
$shm_id = shmop_open(0xff3, "c", 0644, 100);

if(!$shm_id)
{
    echo "Помилка при створенні сегмента розділяється пам'яті.
";
}

/ / Отримуємо розмір сегмента розділяється пам'яті
$shm_size = shmop_size($shm_id);
echo "Блок розділяється пам'яті з розміром:". $shm_size . "Створений.
";

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

if($shm_bytes_written != strlen("Мій блок розділяється пам'яті"))
{
    echo "Помилка при спробі записати дані повністю
";
}

/ / Прочитуємо записану рядок
$my_string = shmop_read($shm_id, 0, $shm_size);

if(!$my_string)
{
    echo "Помилка при спробі читання розділяється пам'яті
";
}

echo "Дані в розділяється пам'яті рівні:".$my_string."
";

/ / Видаляємо блок і закриваємо сегмент розділяється пам'яті

if(!shmop_delete($shm_id))
{
    echo "Помилка при спробі позначити блок розділяється пам'яті на видалення.";
}

shmop_close($shm_id);

?>


Для більш докладної інформації про цих або інших функціях звертайтеся до
офіційною

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Метки: , , , , , ,
Рубрики: Система

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*