Теорія операційної системи

:: Меню ::

Головна
Представлення даних в обчислювальних системах
Машинні мови
Завантаження програм
Управління оперативною пам'яттю
Сегментна і сторінкова віртуальна пам'ять
Комп'ютер і зовнішні події
Паралелізм з точки зору програміста
Реалізація багатозадачності на однопроцесорних комп'ютерах  
Зовнішні пристрої
Драйвери зовнішніх пристроїв
Файлові системи
Безпека
Огляд архітектури сучасних ОС

:: Друзі ::

Карта сайту
 

:: Статистика ::

 

 

 

 

 

 

Завантаження програм

З'ясувавши, що є програма, давайте розглянемо процедуру її завантаження в оперативну пам'ять комп'ютера (багато з обговорюваних далі концепцій, втім, певною мірою застосовні і до прошивки програми в ПЗП).
Спершу передбачимо, що програма була заздалегідь зібрана в якийсь єдиний самодостатній об'єкт, званий завантажувальним або завантажуваним модулем. У ряді операційних систем програма збирається у момент завантаження з великого числа окремих модулів, що містять заслання один на одного, але про це нижче.
Для того, щоб не плутатися, давайте називатимемо програмою ту частину завантажувального модуля, яка містить виконуваний код. Результат завантаження програми в пам'ять називатимемо процесом або, якщо нам треба відрізняти завантажену програму від процесу її виконання образом процесу. До образу процесу інколи зараховують не лише код і дані процесу (піддані перетворенню як в процесі завантаження, так і в процесі роботи програми), але і системні структури даних, пов'язані з цим процесом. У старій літературі процес часто називають завданням.
У системах з віртуальною пам'яттю кожному процесу зазвичай виділяється свій адресний простір, тому ми інколи використовуватимемо термін процес і в цьому сенсі. Втім, в багатьох системах значна частина едресних просторів різних процесів перекривається — це використовується Для реалізації коди, що розділяється, і даних.
В рамках одного процесу може виконуватися один або декілька потоків або ниток управління . Це поняття детальніше знатиметься на главі 8.
Деякі системи надають і крупніші структурні одиниці, Ніж процес. Наприклад, в системах сімейства Unix існують групи процесів, які використовуються для реалізації логічного об'едіненіяют не лише код і дані процесу (піддані перетворенню як в процесі завантаження, так і в процесі роботи програми), але і системні структури даних, пов'язані з цим процесом. У старій літературі процес часто називають завданням.
У системах з віртуальною пам'яттю кожному процесу зазвичай виділяється свій адресний простір, тому ми інколи використовуватимемо термін процес і в цьому сенсі. Втім, в багатьох системах значна частина едресних просторів різних процесів перекривається — це використовується Для реалізації коди, що розділяється, і даних.
В рамках одного процесу може виконуватися один або декілька потоків або ниток управління. Це поняття детальніше розбиратиметься в главі 8.
Деякі системи надають і крупніші структурні одиниці, ніж процес. Наприклад, в системах сімейства Unix існують групи процесів, які використовуються для реалізації логічного об'єднання процесів в завдання (job). Ряд систем мають також поняття сесії — сукупності всіх завдань, які користувач запустив в рамках одного сеансу роботи. Втім, відповідні концепції часто погано визначені, а їх сенс сильно міняється від однієї ОС до іншої, тому ми практично не обговорюватимемо ці поняття.
У старіших системах і в старій літературі називають результат завантаження завданням, а процесами — окремі нитки управління.
Проте в найбільш поширених нині ОС сімейств Unix і Win32, прийнято завдання називати процесом, а процес — ниткою (tread).
Цій термінології ми і дотримуватимемося, окрім тих випадків, коли обговорюватимемо приклади з життя ОС, в якій прийнята інша термінологія.

Створення процесів в Unix
У системах сімейства Unix нові процеси створюються системним викликом fork. Цей виклик створює два процеси, образи яких в перший момент повністю ідентичні, у них розрізняється лише значення, повернене викликом fork. Типова програма, що використовує цей виклик, виглядає так, як представлено в прикладі 3.1.
При цьому кожен з процесів має свою копію всіх локальних і статичних змінних. На процесорах із сторінковим диспетчером пам'яті фізичного копіювання не відбувається. Спочатку обидва процеси використовують одні і ті ж сторінки пам'яті, а дублюються лише ті з них, які були змінені. На системах, що не мають сторінкового або сегментного диспетчера пам'яті, fork вимагає копіювання адресних просторів, що приводить до великих накладних витрат, та і просто не завжди можливо.
Якщо ми хочемо запустити іншу програму, то ми повинні виконати системний виклик з сімейства exec. Виклики цього сімейства розрізняються лише способом передачі параметрів. Всі вони припиняють виконання поточного образу процесу і створюють новий процес з новим віртуальним адресним простором, але з тим же ідентифікатором процесу. При цьому в нового процесу буде той же пріоритет, будуть відкриті ті ж файли (це часто використовується), і він успадкує ряд інших важливих характеристик.
Декілька неочікуваний, але проте вірний опис дії exec — це заміна образу процесу в рамках того ж самого процесу.
Запуск іншої програми в UNIX виглядає приблизно так, як представлено в прикладі 3.2.
Програма в прикладі 3.2 запускає командний інтерпретатор /bin/sh, відомий як Bourne shell, наказує йому виконати команду Is -1 і перенаправляє стандартне виведення цієї команди у файл ls.log.
Техніка програмування, заснована на fork/exec, декілька відрізняється від прийнятої в багатьох інших сучасних системах, у тому числі Win32, де при створенні нового процесу ми відразу ж вказуємо програму, яку він виконуватиме.

Приклад 3.1. Створення процесу в системах сімейства Unix

;nt pid; /* Ідентифікатор породженого процесу */
switch(pid = fork())
I
case 0: /* Породжений процес */
break; case -1: /ошибка */
perror("Cannot fork");
extt(l); default: /* Батьківський процес */
/* Тут ми можемо посилатися на породжений процес
* використовуючи значення pid */

Приклад 3.2. Створення процесу і заміна програми в системах сімейства Unix

int pid; /* Ідентифікатор породженого процесу */
switch (pid = fork () )
{
case 0: /* Породжений процес */
dup2(l, open("Is.log", 0_wronly I 0_creat)); /* Перенаправити відкритий файл #1 * (stdout) у файл Is.log */
execl("/bin/sh", "sh", "-c", "Is", "-1", 0);
/* Сюди ми потрапляємо лише при помилці! */
/* fall through */ case -1: /* Помилка */
perror("Cannot fork or exec");
exit(1); default: /* Батьківський процес */
/* Тут ми можемо посилатися на породжений
* процес, використовуючи значення pid */
}

Але повернемося до способів завантаження програм.

 

:: Реклама ::

 

:: Посилання ::


 

 

 


Copyright © Kivik, 2017