Операционные системы для разработчиков программного обеспечения. (Лекция 2)

Содержание

Слайд 2

План курса

Введение
Что такое ОС? Зачем они нужны?
Основные идеи и принципы ОС
Ядро ОС,

План курса Введение Что такое ОС? Зачем они нужны? Основные идеи и
планировщик, прерывания, многозадачность
Процессы, потоки и таймеры
Многозадачность
Процессы, потоки, средства IPC в Windows и POSIX
Работа с таймерами и временем в Windows и POSIX
Средства разработки кроссплатформенных приложений
Сеть
Принцип построения сетей, стек протоколов TCP\IP
Интерфейсы создания сетевых приложений Windows и POSIX
Маршаллинг данных, средства RPC

Слайд 3

План лекции

Многозадачность
Понятие и виды многозадачности
Потоки и процессы
IPC в Windows и POSIX
Средства IPC
Механизмы

План лекции Многозадачность Понятие и виды многозадачности Потоки и процессы IPC в
синхронизации
Таймеры и время
Особенности таймеров ОС
Работа со временем и календарем в Windows и POSIX
Разработка кроссплатформенных приложений на C/C++
Предопределенные макросы компиляторов
Средства автоматизации сборки
Функции библиотек Boost и QT для реализации IPC и работы со временем

Слайд 4

Перед началом…

Где смотреть описание функций API ОС?
для Microsoft Windows:
MSDN (Microsoft Developer Network):
https://docs.microsoft.com/en-us/windows/win32/

Перед началом… Где смотреть описание функций API ОС? для Microsoft Windows: MSDN

для POSIX:
The Open Group Base Specifications Issue:
https://pubs.opengroup.org/onlinepubs/9699919799/
для Linux:
Linux man pages online:
https://man7.org/linux/man-pages/index.html
BONUS!
В нашей директории на ЯДиске

Слайд 5

Многозадачность, типы, потоки и процессы, механизмы синхронизации: мьютекс, семафор, барьер, IPC

Многозадачность

Многозадачность, типы, потоки и процессы, механизмы синхронизации: мьютекс, семафор, барьер, IPC Многозадачность

Слайд 6

Многозадачность

Одновременное выполнение нескольких подпрограмм (потоков)
ОС сама переключает подпрограммы
вытесняющая: ОС не ждёт завершения

Многозадачность Одновременное выполнение нескольких подпрограмм (потоков) ОС сама переключает подпрограммы вытесняющая: ОС
подпрограммы
невытесняющая: ОС ждёт завершения подпрограммы

Поток 1

Поток 2

Планировщик задач

Поток 1

Слайд 7

Многозадачность

Невытесняющая многозадачность (tickless-система)
совместная, кооперативная многозадачность
планировщик вызывается по окончанию очередной задачи
(-) одна «повисшая»

Многозадачность Невытесняющая многозадачность (tickless-система) совместная, кооперативная многозадачность планировщик вызывается по окончанию очередной
задача блокирует остальные
(+) пониженный расход энергии
(+) легко программировать
применяется в большинстве современных ОС МК
Вытесняющая многозадачность
планировщик вызывается по прерыванию таймера
(+) одна «повисшая» задача не останавливает остальные
надежность системы значительно выше
(-) повышенный расход энергии
(-) необходимость использовать механизмы синхронизации, принципы реентрабельности и потоковой безопасности
применяется в большинстве ОС современных компьютеров и мобильных устройств

Слайд 8

Потоки и процессы

Процесс – выполняется в отдельном виртуальном адресном пространстве и имеет

Потоки и процессы Процесс – выполняется в отдельном виртуальном адресном пространстве и
приоритет исполнения.
Поток (нить) исполнения – выполняется в общем адресном пространстве процесса и, в некоторых ОС, может иметь приоритет исполнения.
В большинстве ОС понятия поток (нить) и процесс неравнозначны.
Для контроля доступа к общей памяти необходимо использовать средства IPC и\или механизмы синхронизации. Для потоков и процессов доступный набор средств может быть различен.

Слайд 9

Создание процесса POSIX

Создание процесса POSIX

Слайд 10

Замещение тела процесса POSIX

Новая программа загружается в память вместо старой, вызвавшей exec().

Замещение тела процесса POSIX Новая программа загружается в память вместо старой, вызвавшей
Старой программе больше недоступны сегменты памяти – они перезаписаны новой программой!
Функции с именем, оканчивающимся на e позволяют задать новый список переменных окружения, вместо стандартных
Доступ к переменным окружения:
int main(int argc, char *argv[], char * envp[]);
: char * getenv( const char *name );
: extern char ** environ;

Слайд 11

POSIX: функция system()

: int system(const char *command);

POSIX: функция system() : int system(const char *command);

Слайд 12

POSIX: функция spawn()

Функция spawn() запускает исполнимый файл и передает управление обратно вызвавшему

POSIX: функция spawn() Функция spawn() запускает исполнимый файл и передает управление обратно
процессу

Подождать завершение созданного процесса можно через waitpid()

Слайд 13

Создание процесса Windows

Создание процесса Windows

Слайд 14

Создание процесса Windows

Можно, как и в POSIX, использовать функцию system() (объявлена в

Создание процесса Windows Можно, как и в POSIX, использовать функцию system() (объявлена
):
Нужно учитывать, что исполняться содержимое будет в Windows console:
EXE-файлы
BAT и CMD скрипты
Список команд

Слайд 15

Создание потока в POSIX

Создание потока в POSIX

Слайд 16

Управление потоками POSIX

Управление потоками POSIX

Слайд 17

Создание потока Windows

Создание потока Windows

Слайд 18

Управление потоками Windows

Управление потоками Windows

Слайд 19

IPC

Межпроцессное взаимодействие (inter-process communication, IPC) — обмен данными между потоками одного или

IPC Межпроцессное взаимодействие (inter-process communication, IPC) — обмен данными между потоками одного
разных процессов. Реализуется посредством механизмов, предоставляемых ядром ОС или процессом, использующим механизмы ОС и реализующим новые возможности IPC. Может осуществляться как на одном компьютере, так и между несколькими компьютерами сети.
Файл (все ОС)
Сигнал (большинство ОС, но не Windows)
Неименованный канал (POSIX, Windows)
Именованный канал (POSIX, Windows)
Разделяемая память (POSIX, Windows)
Сокет (большинство ОС)
Обмен сообщениями (сторонние относительно ОС средства)

Слайд 20

Работа с файлами

Работа с файлами

Слайд 21

Сигналы в POSIX

Сигналы могут быть посланы:
ядром системы для информирования приложения об ошибках

Сигналы в POSIX Сигналы могут быть посланы: ядром системы для информирования приложения
или событиях ввода-вывода
пользователем из терминала, по нажатию специальных комбинаций клавиш: CTRL+C, CTRL+Z и т.п.
из другого приложения:
int kill(pid_t pid, int sig);
Каждый процесс имеет свою маску сигналов (игнорируемые сигналы) и может задавать обработчики сигналов
Обработчик по-умолчанию закрывает программу
Потокам можно отправлять сигналы из основного процесса, у них есть маски, но нет возможности задать обработчик
Внутри обработчика сигнала безопасно можно менять только значения переменных, объявленных с ключевым словом volatile

Слайд 22

Неименованный канал (pipe)

Доступен только связанным процессам – родительскому и дочернему
Использует стратегию работы

Неименованный канал (pipe) Доступен только связанным процессам – родительскому и дочернему Использует
с данными FIFO
Прочитанная информация немедленно удаляется из канала
При чтении из пустого канала процесс блокируется до поступления данных
Неименованный канал создается:
POSIX: int pipe(int fildes[2]) из
Windows:
BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize);
Для чтения и записи из\в канал можно использовать обычные функции работы с файлами:
POSIX: read(), write() из
Windows: ReadFile() WriteFile()

Слайд 23

Именованный канал (named pipe)

В POSIX именованный канал существует независимо от использующих его

Именованный канал (named pipe) В POSIX именованный канал существует независимо от использующих
процессов и имеет имя в системе.
Для создания канала используется
int mkfifo(const char *path, mode_t mode) (из )
программа mkfifo
работать с каналом можно как с обычным файлом (fopen(), fread(), fwrite())
Для удаления канала нужно использовать
int remove(const char *path);
программа rm
Именованные каналы можно использовать с перенаправлением ввода\вывода и любыми программами, которые работают с обычными файлами и\или потоками
В Windows именованные каналы организуют клиент-серверное взаимодействие. Имеют имя \\.\pipe\имя и удаляются, когда никто их не использует
Создание канала: CreateNamedPipe()
Ожидание подключения на стороне сервера: ConnectNamedPipe()
На стороне клиента: CreateFile(), CloseHandle(), ReadFile(), WriteFile() или функции fopen(), fclose(), fread(), fwrite()
Пример сервера:
https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-server-using-overlapped-i-o
Пример клиента:
https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipe-client

Слайд 24

Разделяемая память в POSIX

Область памяти, одновременно доступная в разных процессах
Самый быстрый IPC
В

Разделяемая память в POSIX Область памяти, одновременно доступная в разных процессах Самый
POSIX для работы используются:
#include
shm_open() – связать область памяти с файловым дескриптором
ftruncate() из для изменения размера области
mmap() для подключения разделяемой памяти к адресному пространству процесса
после подключения с памятью можно работать через обычный указатель
обязательно необходимо использовать примитивы синхронизации – семафоры
https://habr.com/ru/post/122108/

Слайд 25

Разделяемая память в Windows

CreateFileMapping() для создания глобально именованной области, с указанием размера
OpenFileMapping()

Разделяемая память в Windows CreateFileMapping() для создания глобально именованной области, с указанием
для открытия глобально именованной области памяти
MapViewOfFile() для подключения памяти к адресному пространству процесса и получения указателя на нее
UnmapViewOfFile() для отключения памяти от локального адресного пространства
Когда последний процесс вызовет эту функцию, содержимое памяти очистится и объект удалится
Для разграничения доступа можно использовать любые именованные примитивы синхронизации.
LsaAllocateSharedMemory() – не для того!

Слайд 26

Сокеты Беркли

Сокеты впервые появились в ОС Berkeley UNIX 4.2 BSD (1983 г)
Сокет

Сокеты Беркли Сокеты впервые появились в ОС Berkeley UNIX 4.2 BSD (1983
в POSIX-системе это «файл» специального вида
Все, что записывается в файл, передается по сети
Все, что получено из сети, можно прочитать из файла
Передача данных по сети скрыта от программиста
Сокеты - де-факто стандарт интерфейсов для транспортной подсистемы
Сокеты (разной реализации) поддерживаются практически во всех современных ОС и ЯП.

Слайд 27

Операции с сокетами

Операции с сокетами

Слайд 28

Сторонние средства IPC/RPC

DCE/RPC (Distributed Computing Environment / Remote Procedure Calls) — бинарный

Сторонние средства IPC/RPC DCE/RPC (Distributed Computing Environment / Remote Procedure Calls) —
протокол на базе различных транспортных протоколов, в том числе TCP/IP и Named Pipes из протокола SMB/CIFS
DCOM (Distributed Component Object Model или «Network OLE») — объектно-ориентированное расширение DCE/RPC, позволяющее передавать ссылки на объекты и вызывать методы объектов через ссылки
ZeroC ICE
JSON-RPC— JavaScript Object Notation Remote Procedure Calls (текстовый протокол на базе HTTP) Спецификация RFC-4627
.NET Remoting (бинарный протокол на базе TCP, UDP, HTTP)

Слайд 29

Механизмы синхронизации

При работе с общей памятью из разных потоков или процессов необходимо

Механизмы синхронизации При работе с общей памятью из разных потоков или процессов
использовать механизмы синхронизации.
Мьютекс (Mutex = mutual exclusion) – обеспечивает доступ только одного потока к критическому участку кода; остальные потоки ждут освобождения мьютекса, а потом получают монопольный доступ к критическому участку, в соответствии со своим приоритетом.
Семафор – атомарный счетчик, над которым можно выполнять две операции: уменьшение на 1 (захват) и увеличение на 1 (освобождение). При попытке уменьшения семафора, значение которого равно нулю, задача, запросившая данное действие, должна блокироваться до тех пор, пока не станет возможным уменьшение значения семафора до неотрицательного значения, то есть пока другой процесс не увеличит значение семафора.
Барьер –механизм синхронизации критических точек у группы задач. Задачи могут пройти через барьер только все сразу. Перед входом в критические точки задачи группы должны блокироваться, пока входа в критическую точку не достигнет последняя задача из группы. Как только все задачи окажутся перед входом в свои критические точки, они должны продолжить своё исполнение

Слайд 31

Семафор

Семафор

Слайд 32

Барьер

Барьер

Слайд 33

Синхронизация в POSIX

Семафоры (#include ) – для синхронизации процессов
Неименованный: int sem_init(sem_t *sem,

Синхронизация в POSIX Семафоры (#include ) – для синхронизации процессов Неименованный: int
int pshared, unsigned value);
Именованный: sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
/somename
Работа с семафорами:
int sem_wait(sem_t *sem); - заблокировать семафор
int sem_trywait(sem_t *sem); - проверить семафор
int sem_post(sem_t *sem); - разблокировать семафор
int sem_close(sem_t *sem); - закрыть именованный семафор
int sem_destroy(sem_t *sem); - закрыть неименованный семафор
Мьютексы (#include ) – для синхронизации потоков
Создание и удаление:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Работа:
int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex);
Условные переменные (condition variable) (#include ) - * потоков
Создание\удаление: pthread_cond_init() , pthread_cond_destroy()
Ожидание: pthread_cond_wait(), pthread_cond_timedwait()
Сигнализирование: pthread_cond_signal() , pthread_cond_broadcast()

Слайд 34

Синхронизация в Windows

Для синхронизации процессов используются именованные примитивы:
Мьютексы:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL

Синхронизация в Windows Для синхронизации процессов используются именованные примитивы: Мьютексы: HANDLE CreateMutex(LPSECURITY_ATTRIBUTES
bInitialOwner, LPCTSTR lpName);
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
BOOL ReleaseMutex(HANDLE hMutex);
Семафоры:
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);
Для синхронизации потоков можно использовать неименованные примитивы:
VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
EnterCriticalSection(), TryEnterCriticalSection(), LeaveCriticalSection()
Для ожидания мьютекса или семафора, а также реализации условной переменной нужно использовать:
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds);

Слайд 35

Принцип устройства таймера, работа с датой и временем

Таймеры

Принцип устройства таймера, работа с датой и временем Таймеры

Слайд 36

Таймеры ОС

Аппаратные таймеры
ограниченное число таймеров
всего два программируемых события (будильника) на один таймер
ограниченная

Таймеры ОС Аппаратные таймеры ограниченное число таймеров всего два программируемых события (будильника)
глубина счёта таймера
Таймер в ОС — это программный модуль
использует всего 1 аппаратный таймер (обычно, самый большой из доступных – 32 бита)
ведёт список всех запланированных задач
ставит будильник на ближайшую задачу
по срабатыванию – рассчитывает время до следующей задачи
переставляет будильник на следующую задачу
фиксирует моменты переполнения таймера и корректно их обрабатывает

Слайд 37

Работа со временем в ОС

Аппаратно время отсчитывается RTC (realtime clock)
В настольных компьютерах

Работа со временем в ОС Аппаратно время отсчитывается RTC (realtime clock) В
размещены на материнской плате
Микросхема счета
Кварцевый резонатор
Батарейка
Любая ОС предоставляет функции для работы с датой
Обычно дата представлена в UNIX-time
количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года («эпоха Unix»)
Любая ОС предоставляет функции для замораживания (ожидания таймера или события) потоков и процессов.
Исполнение замороженного процесса откладывается планировщиком до таймаута

Слайд 38

Время в POSIX

Ожидание (#include ):
unsigned sleep(unsigned seconds);
int usleep(useconds_t useconds);
#include :

Время в POSIX Ожидание (#include ): unsigned sleep(unsigned seconds); int usleep(useconds_t useconds);

int nanosleep(const struct timespec *req, struct timespec *rem);
Получить время:
#include : time_t time(time_t *tloc);
#include :
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
Работа с датой (#include ):
struct tm *localtime(const time_t *timer);
struct tm *gmtime(const time_t *timer);
size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
Огромное количество других функций, например clock_* для работы с конкретными часами

Слайд 39

Время в Windows

Ожидание:
VOID Sleep(DWORD dwMilliseconds);
DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable);
Получить время:
#include : time_t

Время в Windows Ожидание: VOID Sleep(DWORD dwMilliseconds); DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable);
time(time_t *tloc);
GetSystemTimeAsFileTime:
Получить дату:
VOID GetSystemTime(LPSYSTEMTIME lpSystemTime);
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime);

Слайд 40

Предопределенные макросы компиляторов,
средства автоматизации сборки,
функции библиотек Boost и QT для реализации IPC

Предопределенные макросы компиляторов, средства автоматизации сборки, функции библиотек Boost и QT для
и работы со временем

Кроссплатформенность в С/C++

Слайд 41

Макросы компиляторов

Кроссплатформенный код на C/C++ обычно пишется с использованием макросов, определяющих ОС,

Макросы компиляторов Кроссплатформенный код на C/C++ обычно пишется с использованием макросов, определяющих
компилятор, аппаратное обеспечение и т.п.
Список предопределенных макросов: https://sourceforge.net/projects/predef/

Слайд 42

Автоматизация сборки

Система автоматизации сборки решает множество задач разработки ПО:
Компиляция объектных модулей
Определение ОС

Автоматизация сборки Система автоматизации сборки решает множество задач разработки ПО: Компиляция объектных
или доступности тех или иных модулей
Линковка объектных модулей в исполняемые файлы
Поиск зависимостей
Выполнение тестов
Развертывание системы в целевой среде
Автоматическое создание документации программиста, описание изменений
Популярные системы автоматизации сборки:
Make (только POSIX системы)
SCons (https://scons.org/)
CMake (https://cmake.org/)
QMake (поставляется с QT)

Слайд 43

Boost и QT

Boost.Threads
Boost.Process
Boost.Interprocess
Boost.Filesystem
Boost.Date_Time

QThread
QProcess
QSharedMemory, QTcpSocket, QTcpServer,…
QFile
QDateTime

https://www.boost.org/doc/libs/1_78_0/?view=categorized
https://doc.qt.io/qt-5/index.html

Boost и QT Boost.Threads Boost.Process Boost.Interprocess Boost.Filesystem Boost.Date_Time QThread QProcess QSharedMemory, QTcpSocket,

Слайд 44

С++11 и С++17

С++11:
std::thread из
std::mutex, std::recursive_mutex, std::condition_variable
std::shared_ptr
std::atomic<>
С++17:
std::filesystem из boost::filesystem
Далее:
Возможно, появятся и

С++11 и С++17 С++11: std::thread из std::mutex, std::recursive_mutex, std::condition_variable std::shared_ptr std::atomic С++17:
сокеты ☺