Повторновикористовна підпрограма

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Комп'ютерна програма або підпрограма є повторновикористовною або інакше повторновхідною (англ. reentrant), якщо вона може бути безпечно викликана знову до завершення роботи її попереднього виклику (тобто вона може бути безпечно виконана паралельно).

Щоб бути повтороновикористовною, комп'ютерна програма або підпрограма:

  • Повинна утриматися від використання статичних (або глобальних) неконастантних даних.
  • Повинна не повертати покажчик на статичні (або глобальні) неконстантні дані.
  • Повинна працювати лише з даними наданими їй підпрограмою, що її викликає.
  • Повинна відмовитись від покладання на блокування ресурсів типу сінглтон.
  • Повинна відмовитись від зміни власного коду.[1] (хіба тільки такого, що виконується в її власному потоковому сховищі)
  • Повинна не викликати неповторновикористовні комп'ютерні програми або підпрограми.

Отримання і пояснення правил[ред. | ред. код]

Підпрограма продукує вихідні дані з вхідних даних (в деяких випадках можна обійтись без вхідних даних і/або не звертати уваги на вихідні). Усі спільні дані можуть бути використані, змінені будь-ким, будь-коли. Якщо дані можуть бути змінені будь-ким (і ніхто не може відслідкувати ці зміни) тоді для тих хто використовує ці дані немає гарантії, що дані не змінились з часу останнього використання.

Дані бувають глобальні та локальні.

Локальні дані не розподіляються між будь-якими, повторновхідними або ні, підпрограмами; значить вони не впливають на повторновхідність. Глобальні дані можуть спільно використовуватись будь-якими підпрограмами, якщо це глобальні змінні, або спільно використовуватись функціями з однаковим ім'ям, якщо це статичні змінні; від того вони можуть впливати на повторновхідність.

  • Не має використовувати статичні (або глобальні) неконстантні дані.

Вірно тільки якщо спільні змінні змінюють адресу під час виконання або коли програма виконується знов. Абсолютні адреси глобальних констант безпечні, якщо тільки вони не змінюються зовні.

  • Не повинна повертати адресу статичних (або глобальних) неконстантних даних.

Звичайні вхідні дані підпрограми ніколи не є спільними, бо кожна підпрограма має свою власну копію.

  • Має працювати тільки з даними забезпеченими викликовою підпрограмою.

Використання блокування має сенс тільки для неконстантних спільних даних. Блокування константних даних не впливає на їх обробку.

  • Не повинна покладатись на блокування ресурсів одинаків.

Операційна система може дозволяти процесу змінювати власний код. Є багато причин, щоб зробити це, але це означає, що наступного разу код може бути відмінним.

  • Повинна відмовитись від модифікації власного коду.

Вона може змінювати себе у випадку розміщення в своїй окремій пам'яті. Це означає, що для кожного нового виклику використовується інше фізичне розташування машинного коду, куди копіюється первісний код.

  • Не має викликати неповторновикористовні програми або підпрограми.

Приклади[ред. | ред. код]

Багаторівневість 'user/object/process priority' та/або багатопроцесорність зазвичай ускладнюють написання повторновикористовного коду. Також, IO коди[уточнити] здебільшого не повторновхідні через використання ресурсу одинака, такого як диск.

Повторновхідність є ключовою властивістю функціонального програмування.

Типово, що рекурсивні підпрограми мають бути повторновхідними. Також підпрограми, що прямо або непрямо викликаються з обробника переривань зазвичай мають бути повторновхідними.

Приклади коду[ред. | ред. код]

В наступному відтинку коду на C, ані f, ані g не є повторновхідними.

int g_var = 1;
 
int f()
{
  g_var = g_var + 2;
  return g_var;
}
 
int g()
{
  return f() + 2;
}

В попередньому коді, f залежить від неконстантної глобальної змінної g_var; таким чином, якщо два потоки викличуть цю підпрограму і використають g_var одночасно, тоді можливе отримання різних результатів в залежності від розподілу часу виконання. Значить, f неповторновхідна. Це ж вірно і для g; вона викликає f, яка є неповторновхідною.

Незначно змінена версія буде повторновхідною:

int f(int i)
{
  return i + 2;
}
 
int g(int i)
{
  return f(i) + 2;
}

Примітки[ред. | ред. код]

  1. "Interrupt Predictability"by Jack Ganssle 1995

Посилання[ред. | ред. код]