Часть II. Операционные системы и системные вызовы
2.1 Введение в операционные системы
2.1.1 Определение и функции операционной системы
Операционная система (ОС) — это основной компонент системного программного обеспечения, который управляет ресурсами вычислительной системы и предоставляет интерфейсы для взаимодействия программ с этими ресурсами. Основной задачей операционной системы является эффективное управление аппаратными средствами компьютера и предоставление программам и пользователям удобного доступа к этим ресурсам.
Основные функции операционной системы:
- Управление процессами: ОС управляет созданием, выполнением, приостановкой и завершением процессов. Она распределяет процессорное время между активными процессами, используя различные алгоритмы планирования.
- Управление памятью: ОС отвечает за распределение и управление памятью для всех процессов. Она обеспечивает выделение памяти, защиту, а также освобождение памяти после завершения процессов.
- Управление файлами: ОС организует доступ к файловой системе, предоставляя интерфейсы для создания, чтения, записи и удаления файлов.
- Управление устройствами ввода-вывода: ОС контролирует и координирует работу с периферийными устройствами (жесткие диски, принтеры, сетевые устройства).
- Безопасность и защита: ОС обеспечивает защиту ресурсов от несанкционированного доступа и предотвращает сбои в системе.
2.1.2 Архитектура операционной системы
Операционные системы могут иметь различные архитектуры, но в общем случае они состоят из следующих компонентов:
- Ядро (kernel): Это центральная часть операционной системы, которая выполняет критические задачи, такие как управление памятью, планирование процессов и обеспечение безопасности. Ядро работает в привилегированном режиме и имеет полный доступ к аппаратуре.
- Системные библиотеки: Они обеспечивают программы функциями, которые работают через системные вызовы. Например, стандартная библиотека языка C (libc) предоставляет интерфейсы для работы с файлами, памятью и процессами.
- Драйверы устройств: Драйверы обеспечивают связь между ОС и аппаратными устройствами, позволяя операционной системе управлять оборудованием через стандартизированные интерфейсы.
- Пользовательский интерфейс: Может быть как командным (CLI), так и графическим (GUI). Это часть системы, которая позволяет пользователям взаимодействовать с компьютером.
2.1.3 Пример операционной системы: Linux
Linux — это одна из самых популярных операционных систем для системного программирования. Linux имеет ядро с открытым исходным кодом и широко используется в серверах, встраиваемых системах, мобильных устройствах и персональных компьютерах. Разработка системного программного обеспечения под Linux имеет свои особенности:
- Используются системные вызовы POSIX.
- Множество утилит для отладки и мониторинга системного ПО (strace, gdb, perf).
- Прямой доступ к коду ядра, что позволяет разрабатывать модули ядра и драйверы устройств.
2.2 Системные вызовы: связь между приложениями и ядром
2.2.1 Что такое системный вызов
Системный вызов — это механизм, с помощью которого программа запрашивает услуги у ядра операционной системы. Системные вызовы позволяют программам выполнять низкоуровневые задачи, такие как работа с файлами, процессами, памятью и устройствами ввода-вывода. Когда приложение вызывает системный вызов, управление передается ядру, которое выполняет необходимые операции с ресурсами системы и возвращает результат приложению.
Примеры типичных системных вызовов:
- Файловая система:
open()
,read()
,write()
,close()
. - Процессы:
fork()
,exec()
,wait()
,exit()
. - Сигналы:
kill()
,signal()
. - Управление памятью:
mmap()
,munmap()
.
2.2.2 Взаимодействие программы с системными вызовами
Каждая программа работает в пользовательском пространстве и не имеет прямого доступа к аппаратным ресурсам компьютера. Для выполнения операций, требующих привилегированного доступа (например, чтение и запись на диск), программа должна обратиться к ядру операционной системы через системные вызовы. Этот процесс выглядит следующим образом:
- Программа делает системный вызов, вызывая соответствующую функцию (например,
write()
для записи в файл). - Управление передается ядру, и процесс переходит в привилегированный режим.
- Ядро выполняет необходимые действия (например, запись данных на диск) и возвращает результат в пользовательский процесс.
- Программа продолжает выполнение.
Системные вызовы обычно реализуются как интерфейсы стандартных библиотек (например, библиотека C). Это означает, что программист взаимодействует с ними через высокоуровневые функции, такие как printf()
, которые в конечном итоге вызывают системные вызовы.
2.2.3 Основные системные вызовы в Linux
-
Работа с файлами:
open()
: Открывает файл и возвращает файловый дескриптор.read()
: Читает данные из файла.write()
: Записывает данные в файл.close()
: Закрывает файл и освобождает ресурсы.
-
Работа с процессами:
fork()
: Создает новый процесс путем копирования текущего процесса (родительского).exec()
: Заменяет образ текущего процесса новым процессом, загружая новую программу в память.wait()
: Ожидает завершения дочернего процесса.exit()
: Завершает выполнение процесса.
-
Управление памятью:
mmap()
: Отображает файл или устройство в память процесса, что позволяет эффективно работать с большими объемами данных.munmap()
: Удаляет отображение из адресного пространства процесса.
-
Сигналы:
kill()
: Отправляет сигнал процессу (например, для его завершения).signal()
: Определяет обработчики сигналов.
2.2.4 Пример использования системного вызова fork()
Пример программы на языке C, использующей системный вызов fork()
для создания нового процесса:
|
|
Объяснение программы:
- Системный вызов
fork()
создает новый процесс. Если вызов успешен, то возвращает два значения: 0 для дочернего процесса и PID дочернего процесса для родительского. - В дочернем процессе программа заменяет текущий образ процесса с помощью системного вызова
exec()
, загружая командуls
для выполнения. - Родительский процесс ожидает завершения дочернего процесса с помощью
wait()
.
2.3 Управление процессами в операционных системах
2.3.1 Понятие процесса и его жизненный цикл
Процесс — это экземпляр программы, который выполняется в системе. Каждый процесс имеет свой контекст выполнения, который включает в себя текущее состояние процессора, данные, память и другие ресурсы, необходимые для выполнения программы. Процессы могут быть созданы, приостановлены, возобновлены и завершены операционной системой.
Жизненный цикл процесса:
- Создание: Процесс создается с помощью системного вызова (например,
fork()
). - Выполнение: Процесс получает процессорное время и выполняет инструкции.
- Ожидание: Процесс может быть переведен в состояние ожидания (например, в ожидании ввода-вывода).
- Завершение: Процесс завершает выполнение, освобождая все выделенные ему ресурсы.
2.3.2 Управление процессами с использованием системных вызовов
Для управления процессами используются следующие системные вызовы:
- Создание процесса:
fork()
- Загрузка новой программы в процесс:
exec()
- Завершение процесса:
exit()
- Ожидание завершения дочернего процесса:
wait()
Практическое задание
Задание:
- Напишите программу на языке C, которая создает новый процесс с использованием системного вызова
fork()
. Дочерний процесс должен запустить командуls
, а родительский процесс должен дождаться его завершения и вывести сообщение о завершении.
Инструкции:
- Используйте системные вызовы
fork()
,exec()
, иwait()
. - В дочернем процессе выполните системную команду
ls
. - В родительском процессе дождитесь завершения дочернего процесса с помощью
wait()
и выведите сообщение.
Заключение к главе 2
В этой главе мы познакомились с основными принципами работы операционных систем и системных вызовов. Мы рассмотрели взаимодействие программ с ядром операционной системы через системные вызовы и управление процессами. В следующей главе мы углубимся в управление памятью и изучим важные аспекты многопоточности и параллелизма.