Як функція копіювання при записі fork () обробляє декілька форк?


23

Згідно з Вікіпедією (що може бути неправильним)

Коли видається системний виклик fork (), створюється копія всіх сторінок, що відповідають батьківському процесу, завантажується в окреме місце пам'яті ОС для дочірнього процесу. Але це не потрібно в певних випадках. Розглянемо випадок, коли дитина виконує " exec" системний виклик (який використовується для виконання будь-якого виконуваного файлу з програми C) або закінчується дуже скоро після fork(). Коли дитині потрібно просто виконати команду для батьківського процесу, немає необхідності в копіюванні сторінок батьківського процесу, оскільки execзамінює адресний простір процесу, який викликав його, командою, яку потрібно виконати.

У таких випадках використовується техніка, яка називається копіювати на запис (COW). За допомогою цієї методики, коли виникає роздвоєння, сторінки батьківського процесу не копіюються для дочірнього процесу. Натомість сторінки діляться між дочірнім та батьківським процесом. Щоразу, коли процес (батько чи дитина) змінює сторінку, окрема копія цієї конкретної сторінки робиться лише для цього процесу (батька чи дитини), який здійснив модифікацію. Потім цей процес використовуватиме щойно скопійовану сторінку, а не загальну у всіх майбутніх посиланнях. Інший процес (той, який не змінив спільну сторінку) продовжує використовувати оригінальну копію сторінки (яка зараз більше не надається). Ця методика називається копіювати при записі, оскільки сторінка копіюється, коли якийсь процес пише на неї.

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

Моє запитання: що відбувається, якщо fork()дзвінки викликаються кілька разів, перш ніж будь-який з процесів зробив спробу записати на загальну сторінку?


У цьому випадку Вікіпедія вірна, просто більш високий рівень.
Діді Кохен

1
Так, копіювання під час запису - це ліниве копіювання, дочірній процес обробляє копію сторінки, коли намагається її написати. Таким чином, після вилки, майже дитяча пам’ять ділиться з батьками. Однак перед будь-яким із здійснених процесів кожен дочірній процес все ще має певну приватну пам'ять, модифіковану від батьківського або нового виділення. Це означає, що навіть без жодних дій процес, що розвивається, має часткову пам'ять. Ми можемо підтвердити це за допомогою pmap -XX PIDабо cat /proc/PID/smap.
де23

Щодо - "Оригінальна сторінка після цього стає позначеною для запису.", Хто їй буде володіти? Ось інший процес, хто не намагався його написати?
Аділь

Це прекрасно. Почнемо це вчити в дитячих садках
ed22

Відповіді:


18

Нічого особливого не відбувається. Усі процеси обмінюються однаковим набором сторінок, і кожна з них отримує свою приватну копію, коли хоче змінити сторінку.


Правильно. Справа в тому, що це дочірній процес, який є особливим, який має завдання копіювати, якщо він намагається записати на загальну сторінку. Ні батько, ні інші діти не знають про зміну, якщо вона зроблена правильно.
Чарльз Стюарт

9
Дитячий процес не такий особливий. І дочірній, і батьківський процеси мають однаковий набір сторінок, які читаються лише після вилки. Що стосується цих сторінок, обробка сторінок є симетричною.
jlliagre

3

Поведінка fork () залежить від того, має * nix система MMU чи ні. У системі, що не належить до MMU (наприклад, на початку PDP-11), виклик системи fork () скопіював усю пам'ять батьків для кожної дитини. У системі * nix на основі MMU * ядро ​​позначає всі сторінки без стеку як R / O і ділиться ними між батьком і дочірньою. Потім, коли будь-який процес записує на будь-яку сторінку, MMU відловлює спробу, ядро ​​потім виділяє сторінку, що записується, і оновлює таблиці сторінок MMU, щоб вказати на сторінку, яку тепер можна записати. Така поведінка Copy-On-Write забезпечує прискорення, оскільки спочатку для кожного дочірнього процесу потрібно виділяти та клонувати лише приватний стек.

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


0

Коли система заздалегідь формує форк (це може залежати від реалізації), вона також позначає сторінки як лише для читання, а батьківський процес - головним процесом цих сторінок.
При спробі запису на ці сторінки виникає помилка сторінки, і ОС бере на себе, копіюючи весь список сторінок або лише змінені (знову ж таки, залежно від реалізації), тому процес написання матиме копію, яку можна записати.
Коли є кілька процесів, розщеплених з одного і того ж, коли "головний" процес записує в пам'ять, інші процеси копіюють їх еквівалентні сторінки.


яка система це робить? linux використовує реалізацію копіювання під час запису
brauliobo

Ось так працює копіювання
напис

3
@DavidKohen - це не те, як працює копіювання на запис у будь-якій його версії, про яку я коли-небудь чув. "Майстерного" процесу немає. Якщо будь-який процес записує спільні сторінки, його копія перетворюється на приватну, а всі інші процеси продовжують ділитися ними.
Селада

1
Я думаю, що Девід Коен має рацію до певного моменту. Це один із способів реалізації копіювання під час запису. Суть полягає в тому, що при такому маркуванні запис на цю сторінку викликає обробку помилок сторінки, яка потім вживатиме відповідних дій, тобто копіювати під час запису. На жаль, ця деталь (яка б була специфічною для системи) є здебільшого не важливою для питання. Майте на увазі, що CoW має два виміри: один, видимий для процесу, і той, як ядро ​​може його реалізувати.
0xC0000022L
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.