03. Объекты ядра и их использование в приложении
Лекция №3. Объекты ядра и их использование в приложении
Курс: Системное программирование (2026–2027)
Учебная программа: 2025, регистрационный № УП-46/2025Пп/уч
Специальность переподготовки: 9-09-0612-02 «Программное обеспечение информационных систем»
Квалификация: Инженер-программист
Тема по программе: Тема 3. Объекты ядра и их использование в приложении (4 академических часа)
Формируемые компетенции: СП-23, СП-24
Введение и цели занятия
📌 Слайд 1: Тема 3. Объекты ядра и их использование в приложении
На предыдущих лекциях мы изучили границу системных вызовов и базовые абстракции операционной системы — процессы и потоки. Однако для практической разработки надежного системного программного обеспечения недостаточно просто запустить параллельные потоки. Когда несколько потоков одновременно обращаются к файлам, сокетам или разделяемой оперативной памяти, возникает проблема несогласованности данных (состояние гонки, Race Condition).
Для безопасного управления разделяемыми ресурсами, межпроцессного взаимодействия и координации потоков операционная система предоставляет фундаментальный механизм — объекты ядра (Kernel Objects).
Цель настоящей лекции — детально изучить архитектуру объектов ядра, внутреннее устройство таблиц дескрипторов, жизненный цикл файлов на системном уровне API, а также примитивы взаимного исключения и синхронизации (мьютексы, семафоры, функции ожидания).
📌 Слайд 2: План лекции
Учебные вопросы лекции:
- Архитектура и жизненный цикл объектов ядра (Kernel Objects).
- Таблица дескрипторов процесса (Process Handle Table), счетчик ссылок и наследование.
- Именованные объекты ядра и пространства имен.
- Системные интерфейсы работы с файлами и сканирования каталогов.
- Проблема состязаний (Race Condition) и концепция критической секции.
- Механизмы синхронизации: сигнальное состояние, мьютексы и семафоры.
- Синхронизация жизненного цикла процессов и потоков через функции ожидания.
1. Архитектура и концепция объектов ядра
📌 Слайд 3: Классификация системных объектов
В операционной системе Windows все ресурсы, с которыми взаимодействует программист, делятся на три категории:
- Объекты пользователя (User Objects): элементы графического интерфейса пользователя — окна (
HWND), меню (HMENU), курсоры, горячие клавиши. Создаются библиотекойuser32.dll. Дескрипторы окон глобальны для оконной станции, не имеют дескрипторов безопасности ядра и автоматически освобождаются при завершении процесса. - Объекты графической подсистемы (GDI Objects): шрифты (
HFONT), перья (HPEN), кисти (HBRUSH), контексты отображения (HDC), растровые изображения (HBITMAP). Управляются библиотекойgdi32.dll. - Объекты ядра (Kernel Objects): структуры данных, монопольно размещаемые в оперативной памяти ядра (Ring 0) и управляемые непосредственно исполнительной подсистемой ОС. К ним относятся:
- файлы и устройства (
File Objects), - процессы и потоки (
Process,Thread Objects), - объекты-задания (
Job Objects), - примитивы синхронизации: мьютексы (
Mutex), семафоры (Semaphore), события (Event), таймеры ожидания (Waitable Timer), - проекции файлов в память (
File Mapping Objects), - межпроцессные каналы (
Pipes) и почтовые ящики (Mailslots).
- файлы и устройства (
📌 Слайд 4: Внутреннее устройство объекта ядра
Объект ядра физически размещается в защищенной памяти ядра и недоступен для прямого чтения или записи прикладным кодом. Если бы приложение могло напрямую изменить поля структуры в памяти, нарушилась бы безопасность всей системы.
Каждый объект ядра состоит из двух логических частей:
- Заголовок объекта ядра (Object Header): стандартизированная структура диспетчера объектов (Object Manager), присутствующая у всех объектов ядра без исключения:
- Указатель типа (Type Object Pointer): определяет категорию ресурса (Файл, Мьютекс, Процесс).
- Счетчик ссылок (Usage Count / Reference Count): количество активных ссылок на данный объект во всей операционной системе.
- Дескриптор безопасности (Security Descriptor, SD): список контроля доступа (DACL), определяющий, каким пользователям и группам (SID) разрешено открывать, читать, модифицировать или удалять данный объект.
- Тело объекта ядра (Object Body): специфические данные конкретного ресурса. Например, для файлового объекта тело содержит текущее смещение чтения/записи (offset) и указатель на кэш; для объекта потока — контекст регистров ЦПУ и состояние планировщика; для мьютекса — идентификатор потока-владельца (Owner TID).

2. Таблица дескрипторов процесса и счетчик ссылок
📌 Слайд 5: Таблица дескрипторов процесса (Handle Table)
Поскольку прикладной процесс в Ring 3 не может оперировать прямыми адресами памяти ядра, операционная система предоставляет косвенный механизм адресации — дескрипторы (Handles).
В структуре ядра EPROCESS каждого процесса выделяется внутренняя Таблица дескрипторов (Handle Table). Она представляет собой массив записей, каждая из которых содержит:
- Указатель на объект ядра в памяти Ring 0.
- Маску предоставленных прав доступа (Access Mask): битовый набор разрешенных операций (например,
GENERIC_READ,SYNCHRONIZE). При каждом вызове функции API ядро сверяет запрошенную операцию с маской доступа дескриптора. - Флаг наследования (Inheritance Flag): определяет, будет ли данный дескриптор скопирован в таблицу дочернего процесса при создании через
CreateProcessW.
Сам тип HANDLE в коде на языке Си — это не числовой дескриптор файла и не физический указатель, а смещение (индекс, кратный 4 байтам) внутри таблицы дескрипторов текущего процесса. Значение HANDLE локально: одно и то же числовое значение (например, 0x00000004) в двух разных процессах ссылается на совершенно разные объекты ядра.
📌 Слайд 6: Счетчик ссылок (Usage Count) и закрытие CloseHandle
Объекты ядра существуют независимо от процессов, которые их создали. Жизненный цикл объекта ядра регулируется механизмом подсчета ссылок (Usage Count):
- Создание объекта: когда процесс вызывает функцию создания ресурса (например,
CreateFileWилиCreateMutexW), ядро выделяет память под объект и инициализирует счетчик ссылокUsage Count = 1. В таблицу дескрипторов процесса добавляется запись, а функция возвращает дескрипторHANDLE. - Дублирование и разделение: если другой процесс открывает тот же именованный мьютекс через
OpenMutexWили наследует дескриптор, в его таблицу дескрипторов вносится новая запись, указывающая на тот же физический объект ядра, аUsage Countувеличивается до 2. - Закрытие дескриптора: при вызове
CloseHandle(h)ядро удаляет соответствующую запись из таблицы дескрипторов вызывающего процесса и атомарно декрементируетUsage Count. - Уничтожение объекта: объект ядра удаляется из оперативной памяти ядра только тогда, когда его счетчик ссылок становится равным нулю.
Важно: Закрытие дескриптора процесса
CloseHandle(pi.hProcess)не приводит к остановке самого процесса! Процесс продолжает выполняться на процессоре. Закрытие дескриптора лишь сообщает ядру, что данный родительский процесс больше не планирует опрашивать дочерний процесс через этотHANDLE. Пока процесс активен, ядро само удерживает внутреннюю ссылку на объект процесса, поэтомуUsage Countне упадет до нуля до фактического завершения процесса.
📌 Слайд 7: Наследование и дублирование дескрипторов
1. Механизм наследования дескрипторов
По умолчанию дескрипторы создаются ненаследуемыми. Чтобы разрешить дочернему процессу унаследовать дескриптор, необходимо:
- При создании объекта передать указатель на структуру
SECURITY_ATTRIBUTESс установленным флагомbInheritHandle = TRUE:
1SECURITY_ATTRIBUTES sa;
2sa.nLength = sizeof(sa);
3sa.lpSecurityDescriptor = NULL;
4sa.bInheritHandle = TRUE; // Разрешить наследование
5
6HANDLE hFile = CreateFileW(L"log.txt", GENERIC_WRITE, 0, &sa,
7 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- При запуске дочернего процесса передать флаг
bInheritHandles = TRUEв функциюCreateProcessW:
1CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
При этом ядро дублирует записи с установленным флагом наследования в таблицу дескрипторов дочернего процесса под теми же числовыми индексами HANDLE и инкрементирует счетчик Usage Count соответствующих объектов ядра.
2. Дублирование через DuplicateHandle
Если процессу требуется передать дескриптор в уже работающий процесс без родственных связей (наследования), применяется системный вызов DuplicateHandle():
1DuplicateHandle(
2 hSourceProcess, // Дескриптор исходного процесса
3 hSourceHandle, // Исходный дескриптор
4 hTargetProcess, // Дескриптор целевого процесса
5 &hTargetHandle, // Выходной дескриптор для целевого процесса
6 0, // Желаемый доступ
7 FALSE, // Наследование в целевом процессе
8 DUPLICATE_SAME_ACCESS// Скопировать маску доступа без изменений
9);
3. Именованные объекты ядра и пространства имен
📌 Слайд 8: Именованные объекты ядра и пространства имен
Многие объекты ядра (мьютексы, семафоры, события, проекции файлов) могут создаваться с символическими строковыми именами (Named Objects). Имя объекта регистрируется в глобальном дереве диспетчера объектов ядра Windows.
Именованные объекты ядра служат основным средством обнаружения ресурсов при межпроцессном взаимодействии (IPC):
- Процесс A создает объект вызовом
CreateMutexW(NULL, FALSE, L"Global\\MySystemSyncMutex");. - Процесс B подключается к уже созданному объекту вызовом
OpenMutexW(SYNCHRONIZE, FALSE, L"Global\\MySystemSyncMutex");.
Пространства имен объектов:
Global\: объекты ядра доступны во всех сессиях пользователей операционной системы (включая системные службы и службы терминалов RDP). Требуются повышенные привилегии администратораSeCreateGlobalPrivilege.Local\: объекты ядра изолированы в рамках текущей пользовательской сессии (сессии входа в систему).
Паттерн «Единственный экземпляр приложения» (Single Instance):
Классическая задача системного программирования — запретить запуск второй копии программы на одном компьютере:
1#include <windows.h>
2#include <stdio.h>
3
4int main(void) {
5 // Создаем именованный мьютекс
6 HANDLE hMutex = CreateMutexW(NULL, FALSE, L"Local\\MyUniqueApplicationLock");
7
8 // Проверяем, существовал ли объект в ядре до нашего вызова
9 if (GetLastError() == ERROR_ALREADY_EXISTS) {
10 printf("Приложение уже запущено! Завершение второй копии.\n");
11 CloseHandle(hMutex);
12 return 0;
13 }
14
15 printf("Приложение успешно запущено в единственном экземпляре.\n");
16 // Основной цикл программы...
17 getchar();
18
19 CloseHandle(hMutex);
20 return 0;
21}
4. Системные интерфейсы работы с файлами
📌 Слайд 9: Системный ввод-вывод: CreateFileW, ReadFile, WriteFile
Файл в операционной системе Windows является объектом ядра. В отличие от стандартной библиотеки Си (fopen, fread, использующих буферизацию в пространстве пользователя), системные функции WinAPI обращаются напрямую к драйверу файловой системы.
Создание и открытие: CreateFileW
Универсальная функция, открывающая файлы, каталоги, физические диски, COM-порты и именованные каналы:
1HANDLE hFile = CreateFileW(
2 L"C:\\data\\records.dat", // Путь к файлу
3 GENERIC_READ | GENERIC_WRITE, // Желаемый доступ (чтение/запись)
4 FILE_SHARE_READ, // Режим совместного доступа
5 NULL, // Атрибуты безопасности по умолчанию
6 OPEN_ALWAYS, // Открыть если есть, создать если нет
7 FILE_ATTRIBUTE_NORMAL, // Атрибуты файла
8 NULL // Шаблонный файл
9);
10
11if (hFile == INVALID_HANDLE_VALUE) {
12 DWORD err = GetLastError();
13 // Обработка ошибки...
14}
Чтение и запись: ReadFile и WriteFile
Операции чтения и записи требуют явного указания размера буфера и переменной для сохранения фактического числа переданных байт:
1char buffer[1024];
2DWORD bytesRead;
3BOOL bSuccess = ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL);
4
5DWORD bytesWritten;
6bSuccess = WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL);
📌 Слайд 10: Позиционирование указателя файла: SetFilePointerEx
Файловый объект ядра хранит 64-битный указатель текущей позиции чтения/записи (File Offset). Каждое успешное чтение или запись автоматически смещает этот указатель вперед.
Для произвольного перемещения по файлу в WinAPI применяется функция SetFilePointerEx:
1LARGE_INTEGER distance;
2LARGE_INTEGER newPosition;
3
4// Смещение на 4096 байт от начала файла
5distance.QuadPart = 4096;
6
7BOOL bResult = SetFilePointerEx(
8 hFile, // Дескриптор открытого файла
9 distance, // Смещение (структура LARGE_INTEGER, 64 бита)
10 &newPosition, // Переменная для записи новой позиции
11 FILE_BEGIN // Точка отсчета
12);
Методы точки отсчета:
FILE_BEGIN: смещение отсчитывается от начала файла (эквивалентSEEK_SETв POSIXlseek).FILE_CURRENT: смещение относительно текущей позиции (SEEK_CUR).FILE_END: смещение от конца файла (SEEK_END, используется для определения размера файла или дозаписи в конец).
📌 Слайд 11: Сканирование файловой системы: FindFirstFileW и FindClose
Для обхода файлов и подкаталогов в Windows применяется специализированная итерационная модель:
1#include <windows.h>
2#include <stdio.h>
3
4void ScanDirectory(LPCWSTR pathMask) {
5 WIN32_FIND_DATAW findData;
6 HANDLE hFind = FindFirstFileW(pathMask, &findData);
7
8 if (hFind == INVALID_HANDLE_VALUE) {
9 printf("Файлы не найдены или каталог недоступен.\n");
10 return;
11 }
12
13 do {
14 // Проверяем, является ли запись подкаталогом
15 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
16 wprintf(L"[КАТАЛОГ] %s\n", findData.cFileName);
17 } else {
18 // Вычисляем размер 64-битного файла
19 ULARGE_INTEGER fileSize;
20 fileSize.LowPart = findData.nFileSizeLow;
21 fileSize.HighPart = findData.nFileSizeHigh;
22 wprintf(L"[ФАЙЛ] %s (%llu байт)\n", findData.cFileName, fileSize.QuadPart);
23 }
24 } while (FindNextFileW(hFind, &findData));
25
26 // Обязательное закрытие дескриптора поиска ядра
27 FindClose(hFind);
28}
Важно: Функция
FindClose(hFind)является критически необходимой. Дескриптор поискаhFindудерживает контекст сканирования директории и выделенные буферы ядра файловой системы. Ошибка вызоваFindCloseприводит к утечке системных дескрипторов.

5. Проблема состязаний и критические секции
📌 Слайд 12: Проблема состязаний (Race Condition)
Когда два и более параллельных потока разделяют общую память и хотя бы один из них выполняет запись, последовательность операций становится недетерминированной.
Рассмотрим элементарную операцию инкремента переменной в языке Си: counter++:
На уровне машинного кода архитектуры x86/x64 эта строчка распадается на три независимые инструкции:
mov eax, [counter]— чтение значения из ОЗУ в регистр процессора;inc eax— инкремент значения в регистре;mov [counter], eax— запись обновленного значения обратно в ОЗУ.
Если планировщик ядра переключит контекст процессора между шагами 2 и 3, второй поток считает старое значение из памяти. В результате оба потока запишут одно и то же число, и один инкремент будет безвозвратно потерян.
Состояние гонки (Race Condition) — это ошибка проектирования многопоточной программы, при которой результат вычислений зависит от непредсказуемого порядка переключения потоков планировщиком ОС.

📌 Слайд 13: Концепция критической секции и взаимного исключения
Участок программного кода, обращающийся к разделяемому ресурсу (общей памяти, файлу, очереди), называется критической секцией (Critical Section).
Для корректной параллельной работы система синхронизации должна обеспечивать три фундаментальных условия Дейкстры:
- Взаимное исключение (Mutual Exclusion): ни в какой момент времени в критической секции не может находиться более одного потока одновременно.
- Прогресс (Progress): если ни один поток не находится в критической секции, любой ожидающий поток должен получить возможность войти без бесконечной задержки.
- Ограниченное ожидание (Bounded Waiting): время ожидания потока на входе в критическую секцию должно быть конечным; система не должна допускать «голодания» (Starvation) отдельных потоков.
6. Механизмы синхронизации: сигнальное состояние, мьютексы и семафоры
📌 Слайд 14: Концепция сигнального состояния объектов ядра
В операционной системе Windows все примитивы синхронизации построены на концепции бинарного флага ядра: объект может находиться либо в сигнальном (Signaled), либо в несигнальном (Nonsignaled) состоянии.
Поведение функции ожидания WaitForSingleObject(hObject, timeout):
- Если объект находится в сигнальном состоянии, функция немедленно завершается успешно (возвращает
WAIT_OBJECT_0), а поток продолжает исполнение. - Если объект находится в несигнальном состоянии, ядро переводит вызывающий поток в состояние ожидания (Blocked) и исключает его из очереди планировщика. Поток спит, пока объект не перейдет в сигнальное состояние либо пока не истечет указанный таймаут.

📌 Слайд 15: Мьютексы (Mutex) в системном API
Мьютекс (Mutex, от Mutual Exclusion) — это объект ядра, предназначенный для обеспечения взаимоисключающего доступа к ресурсу.
Особенности объекта-мьютекса в Windows:
- Состояние: мьютекс находится в сигнальном состоянии, когда он свободен (никому не принадлежит). При захвате потоком мьютекс переходит в несигнальное состояние.
- Владение (Thread Ownership): ядро строго отслеживает идентификатор потока (
TID), владеющего мьютексом. Освободить мьютекс вызовомReleaseMutex()может только тот поток, который его захватил. - Потоко-рекурсивность (Recursion Count): если поток, уже владеющий мьютексом, повторно вызывает
WaitForSingleObjectна этот же мьютекс, вызов не приводит к взаимной блокировке (Deadlock). Ядро просто инкрементирует внутренний счетчик рекурсии. Чтобы мьютекс стал доступен другим потокам, поток-владелец должен вызватьReleaseMutexровно столько же раз. - Брошенный мьютекс (Abandoned Mutex): если поток захватил мьютекс и неожиданно завершился (падение,
ExitThread,TerminateThread), не вызвавReleaseMutex, операционная система автоматически переводит мьютекс в сигнальное состояние, а следующему ждущему потоку возвращает специальный кодWAIT_ABANDONED. Это предотвращает вечную блокировку системы.
1HANDLE hMutex = CreateMutexW(NULL, FALSE, NULL);
2
3// Захват мьютекса
4DWORD dwWait = WaitForSingleObject(hMutex, INFINITE);
5if (dwWait == WAIT_OBJECT_0) {
6 // Безопасная работа с общими данными в критической секции
7 counter++;
8 // Обязательное освобождение мьютекса
9 ReleaseMutex(hMutex);
10}
📌 Слайд 16: Семафоры (Semaphore) в системном API
Семафор (Semaphore) — это объект ядра, поддерживающий счетчик доступных ресурсов в диапазоне от 0 до заданного максимума $N$.
Принцип работы семафора:
- Если счетчик семафора строго больше 0, семафор находится в сигнальном состоянии.
- Если счетчик семафора равен 0, семафор переходит в несигнальное состояние (ресурсы исчерпаны).
Каждый вызов WaitForSingleObject на семафор при значении счетчика $>0$ атомарно уменьшает счетчик на 1.
Функция ReleaseSemaphore(hSem, count, &prevCount) атомарно увеличивает счетчик на указанное число.
1// Семафор с начальным счетчиком 3 и максимальным 3 (пул из 3 подключений)
2HANDLE hSem = CreateSemaphoreW(NULL, 3, 3, NULL);
3
4// Захват одного слота из пула
5WaitForSingleObject(hSem, INFINITE);
6
7// Использование ресурса...
8
9// Возврат слота в пул (+1 к счетчику)
10ReleaseSemaphore(hSem, 1, NULL);
Отличия семафора от мьютекса:
| Характеристика | Мьютекс (Mutex) | Семафор (Semaphore) |
|---|---|---|
| Назначение | Взаимное исключение (1 поток) | Ограничение доступа к пулу ресурсов ($N$ потоков) |
| Понятие владельца | Есть (только владелец может освободить) | Нет (любой поток может вызвать ReleaseSemaphore) |
| Рекурсивный захват | Поддерживается (счетчик рекурсии) | Не поддерживается (каждый вызов уменьшает счетчик) |
| Обработка падения потока | Сигнализирует WAIT_ABANDONED | Нет защиты от завершения потока |
📌 Слайд 17: Функция множественного ожидания WaitForMultipleObjects
В реальных приложениях потоку часто требуется ожидать наступления событий от нескольких объектов ядра одновременно (например, завершение рабочего потока или сигнал аварийной остановки программы).
Для этого применяется функция WaitForMultipleObjects:
1HANDLE handles[2];
2handles[0] = hWorkerThread; // Дескриптор потока
3handles[1] = hShutdownEvent;// Дескриптор события завершения
4
5DWORD dwIndex = WaitForMultipleObjects(
6 2, // Число объектов в массиве (максимум MAXIMUM_WAIT_OBJECTS = 64)
7 handles, // Массив дескрипторов
8 FALSE, // bWaitAll: FALSE = ждать ЛЮБОЙ объект, TRUE = ждать ВСЕ объекты
9 INFINITE // Таймаут
10);
11
12if (dwIndex == WAIT_OBJECT_0) {
13 printf("Рабочий поток успешно завершил вычисления.\n");
14} else if (dwIndex == WAIT_OBJECT_0 + 1) {
15 printf("Получен сигнал экстренной остановки сервиса!\n");
16}
7. Синхронизация жизненного цикла процессов и потоков
📌 Слайд 18: Синхронизация завершения процессов и потоков
Объекты процессов и потоков сами по себе являются объектами синхронизации ядра:
- Пока процесс или поток выполняется, его объект находится в несигнальном состоянии.
- В момент вызова
ExitProcess/ExitThreadядро навсегда переводит объект в сигнальное состояние.
Безопасное завершение потоков (Cancellation)
В системном программировании считается грубой ошибкой использование принудительного уничтожения потоков функцией TerminateThread():
TerminateThread()мгновенно обрывает выполнение потока на текущей машинной инструкции.- Если поток в этот момент владел памятью кучи, критической секцией или ресурсом ввода-вывода, ресурс останется заблокированным навсегда, приводя к зависанию всей программы.
Правильный паттерн завершения: использование флага остановки на базе объекта-события (Event):
- Главный поток создает событие:
HANDLE hStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Фоновый поток в рабочем цикле периодически проверяет сигнал:
if (WaitForSingleObject(hStopEvent, 0) == WAIT_OBJECT_0) break; - Для остановки главный поток вызывает
SetEvent(hStopEvent)и ожидает корректного выхода фонового потока черезWaitForSingleObject(hThread, INFINITE). - Фоновый поток корректно освобождает все ресурсы, закрывает файлы и вызывает
return.
📌 Слайд 19: Резюме лекции
Основные итоги:
- Объекты ядра размещаются в памяти Ring 0, защищены от прямой модификации прикладным кодом и имеют заголовок со счетчиком ссылок (
Usage Count) и дескриптором безопасности. - Дескрипторы
HANDLEпредставляют собой локальные индексы во внутренней таблице дескрипторов процесса. Они требуют обязательного освобождения черезCloseHandle(). - Именованные объекты ядра регистрируются в пространствах имен
Global\иLocal\, обеспечивая межпроцессную синхронизацию и реализацию паттерна Single Instance. - Файловый ввод-вывод на уровне WinAPI (
CreateFileW,ReadFile,WriteFile,SetFilePointerEx) обеспечивает прямой небуферизованный доступ к данным; сканирование каталогов выполняется через триадуFindFirstFileW/FindNextFileW/FindClose. - Состояние гонки (Race Condition) исключается защитой критических секций примитивами взаимного исключения.
- Мьютекс обеспечивает строгое владение ресурсом одним потоком с поддержкой рекурсии и защиты от бросания (
WAIT_ABANDONED). - Семафор регулирует доступ к пулу из $N$ ресурсов без привязки к потоку-владельцу.
- Функции ожидания (
WaitForSingleObject,WaitForMultipleObjects) переводят поток в эффективный сон ядра до перехода объектов в сигнальное состояние.
📌 Слайд 20: Вопросы для самопроверки
- Чем объекты ядра отличаются от объектов пользователя (User Objects) и графических объектов (GDI Objects)?
- Что происходит с объектом ядра, если один процесс закрывает дескриптор вызовом
CloseHandle, но этот же объект открыт во втором процессе? - Каким образом с помощью функции
CreateMutexWи кода ошибкиERROR_ALREADY_EXISTSгарантировать работу приложения в единственном экземпляре? - Почему для позиционирования в файлах большого размера применяется функция
SetFilePointerEx, а не устаревшаяSetFilePointer? - Почему после сканирования файлов директории функцией
FindNextFileWнеобходимо обязательно вызыватьFindClose? - Что такое критическая секция и какие три условия Дейкстры обязана удовлетворять корректная синхронизация?
- В чем заключается принципиальная разница между объектом-мьютексом и объектом-семафором?
- Что означает код возврата
WAIT_ABANDONEDфункцииWaitForSingleObjectи почему он возникает? - Почему принудительное завершение потока функцией
TerminateThreadсчитается опасной практикой?
📌 Слайд 21: Литература и рекомендуемые ресурсы
Литература по курсу:
- Современные операционные системы (4-е изд.) — Таненбаум Э., Бос Х. СПб.: Питер, 2021. 1119 с.
- Устройство и функционирование OC Windows. Практикум к курсу «Операционные системы» — Коньков К. А. М.: Бином, 2008. 208 с.
- Операционные системы (2-е изд.) — Гордеев А. В. СПб.: Питер, 2009. 415 с.
- Системное программирование: методические указания по выполнению лабораторных работ — Бизюк А. Н., Соколова А. С. Витебск: УО «ВГТУ», 2024.
- Справочник Windows API: Объекты ядра и синхронизация — https://learn.microsoft.com/en-us/windows/win32/sync/synchronization
- Справочник Windows API: Управление файлами — https://learn.microsoft.com/en-us/windows/win32/fileio/file-management