Featured image of post Часть II. Операционные системы и системные вызовы

Часть II. Операционные системы и системные вызовы

Рассмотрение основ операционных систем и системных вызовов, их функций, архитектуры и взаимодействия приложений с ядром ОС

Часть 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 Взаимодействие программы с системными вызовами

Каждая программа работает в пользовательском пространстве и не имеет прямого доступа к аппаратным ресурсам компьютера. Для выполнения операций, требующих привилегированного доступа (например, чтение и запись на диск), программа должна обратиться к ядру операционной системы через системные вызовы. Этот процесс выглядит следующим образом:

  1. Программа делает системный вызов, вызывая соответствующую функцию (например, write() для записи в файл).
  2. Управление передается ядру, и процесс переходит в привилегированный режим.
  3. Ядро выполняет необходимые действия (например, запись данных на диск) и возвращает результат в пользовательский процесс.
  4. Программа продолжает выполнение.

Системные вызовы обычно реализуются как интерфейсы стандартных библиотек (например, библиотека C). Это означает, что программист взаимодействует с ними через высокоуровневые функции, такие как printf(), которые в конечном итоге вызывают системные вызовы.

2.2.3 Основные системные вызовы в Linux

  1. Работа с файлами:

    • open(): Открывает файл и возвращает файловый дескриптор.
    • read(): Читает данные из файла.
    • write(): Записывает данные в файл.
    • close(): Закрывает файл и освобождает ресурсы.
  2. Работа с процессами:

    • fork(): Создает новый процесс путем копирования текущего процесса (родительского).
    • exec(): Заменяет образ текущего процесса новым процессом, загружая новую программу в память.
    • wait(): Ожидает завершения дочернего процесса.
    • exit(): Завершает выполнение процесса.
  3. Управление памятью:

    • mmap(): Отображает файл или устройство в память процесса, что позволяет эффективно работать с большими объемами данных.
    • munmap(): Удаляет отображение из адресного пространства процесса.
  4. Сигналы:

    • kill(): Отправляет сигнал процессу (например, для его завершения).
    • signal(): Определяет обработчики сигналов.

2.2.4 Пример использования системного вызова fork()

Пример программы на языке C, использующей системный вызов fork() для создания нового процесса:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid == -1) {
        // Ошибка при создании процесса
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        // Это дочерний процесс
        printf("Дочерний процесс: PID = %d\n", getpid());
        execl("/bin/ls", "ls", NULL);  // Выполняем другую программу
    } else {
        // Это родительский процесс
        printf("Родительский процесс: PID = %d\n", getpid());
        wait(NULL);  // Ждем завершения дочернего процесса
    }

    return 0;
}

Объяснение программы:

  • Системный вызов fork() создает новый процесс. Если вызов успешен, то возвращает два значения: 0 для дочернего процесса и PID дочернего процесса для родительского.
  • В дочернем процессе программа заменяет текущий образ процесса с помощью системного вызова exec(), загружая команду ls для выполнения.
  • Родительский процесс ожидает завершения дочернего процесса с помощью wait().

2.3 Управление процессами в операционных системах

2.3.1 Понятие процесса и его жизненный цикл

Процесс — это экземпляр программы, который выполняется в системе. Каждый процесс имеет свой контекст выполнения, который включает в себя текущее состояние процессора, данные, память и другие ресурсы, необходимые для выполнения программы. Процессы могут быть созданы, приостановлены, возобновлены и завершены операционной системой.

Жизненный цикл процесса:

  • Создание: Процесс создается с помощью системного вызова (например, fork()).
  • Выполнение: Процесс получает процессорное время и выполняет инструкции.
  • Ожидание: Процесс может быть переведен в состояние ожидания (например, в ожидании ввода-вывода).
  • Завершение: Процесс завершает выполнение, освобождая все выделенные ему ресурсы.

2.3.2 Управление процессами с использованием системных вызовов

Для управления процессами используются следующие системные вызовы:

  • Создание процесса: fork()
  • Загрузка новой программы в процесс: exec()
  • Завершение процесса: exit()
  • Ожидание завершения дочернего процесса: wait()

Практическое задание

Задание:

  • Напишите программу на языке C, которая создает новый процесс с использованием системного вызова fork(). Дочерний процесс должен запустить команду ls, а родительский процесс должен дождаться его завершения и вывести сообщение о завершении.

Инструкции:

  1. Используйте системные вызовы fork(), exec(), и wait().
  2. В дочернем процессе выполните системную команду ls.
  3. В родительском процессе дождитесь завершения дочернего процесса с помощью wait() и выведите сообщение.

Заключение к главе 2

В этой главе мы познакомились с основными принципами работы операционных систем и системных вызовов. Мы рассмотрели взаимодействие программ с ядром операционной системы через системные вызовы и управление процессами. В следующей главе мы углубимся в управление памятью и изучим важные аспекты многопоточности и параллелизма.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy