Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

6 семестр / ОСиСП_ЛР3

.docx
Скачиваний:
0
Добавлен:
18.02.2023
Размер:
23.82 Кб
Скачать

Министерство образования Республики Беларусь

ПОЛОЦКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ

Кафедра технологий программирования

Методические указания для выполнения лабораторной работы № 3

по курсу «Операционные системы и системное программирование»

«Многозадачность в ОС Windows: создание и синхронизация потоков, мьютексы»

Полоцк, 2019

КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

Поток

Первичный поток, который присутствует в программе, начинает свое выполнение с главной функции потока типа main.

Для создания вторичного потока необходимо создать и для него входную функцию, которая выглядит примерно как показано в листинге 1.

Листинг 1 – Шаблон функции потока

DWORD WINAPI ThreadFunc(PVOID pParam)

{

DWORD dwResult = 0;

.........

return dwResult;

}

Имя у функции вторичного потока, в отличии от первичного, может быть любым однако, при наличии нескольких разных потоков, назвать функции необходимо по-разному, иначе система создаст разные реализации одной и той же функции.

Когда поток закончит свое исполнение, он вернет управление системе, память, отведенная под его стек, будет освобождена, а счетчик пользователей его объекта ядра "поток" уменьшится на 1. Когда счетчик обнулится, этот объект ядра будет разрушен.

Для создания своего потока необходимо использовать функцию CreateThread сигнатура которой показана в листинге 2:

Листинг 2 – Сигнатура функции CreateThread

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes,

DWORD dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId);

Параметры функции CreateThread:

LpThreadAttributes - является указателем на структуру LPSECURITY_ATTRIBUTES. Для присвоения атрибутов защиты по умолчанию, передавайте в этом параметре NULL.

DwStackSize - параметр определяет размер стека, выделяемый для потока из общего адресного пространства процесса. При передаче 0 - размер устанавливается в значение по умолчанию.

LpStartAddress - указатель на адрес входной функции потока.

LpParameter - параметр, который будет передан внутрь функции потока.

DwCreationFlags - принимает одно из двух значений: 0 - исполнение начинается немедленно, или CREATE_SUSPENDED - исполнение приостанавливается до последующих указаний.

LpThreadId - Адрес переменной типа DWORD в который функция возвращает идентификатор, приписанный системой новому потоку.

При каждом вызове этой функции система создает объект ядра (поток). Это не сам поток, а компактная структура данных, которая используется операционной системой для управления потоком и хранит статистическую информацию о потоке.

Система выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Поэтому он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.

Поток можно завершит четырьмя способами:

  • функция потока возвращает управление (рекомендуемо);

  • поток самоуничтожается вызовом функции ExitThread;

  • другой поток процесса вызывает функцию TerminateThread;

  • завершается процесс, содержащий данный поток.

При желании немедленно завершить поток изнутри используют функцию ExitThread(DWORD dwExitCode).

Если же вы ее использовали, то кодом возврата потока будет тот параметр, который вы передадите в данную функцию.

Если появилась необходимость уничтожить поток снаружи, то это моет сделать функция TeminateThread. Эта функция уменьшит счетчик пользователей объекта ядра (поток) на 1, однако при этом не разрушит и не очистит стек потока. Стек будет существовать, пока не завершится процесс, которому принадлежит поток. При задачах, постоянно создающих и уничтожающих потоки, это приводит к потере памяти внутри процесса.

События

Событие ( event ) - это флаг общего доступа для нескольких потоков. Существует несколько типов событий, каждый из которых предназначен для конкретной цели. Событие находится в сигнальном состоянии в случае, если соответствующий флаг установлен.

События могут быть мануальными ( manual ) и единичными ( single ), соответственно оповещающие о том что событие произошло либо множество потоков сразу, либо единственный поток, после чего событие сбрасывается системой автоматически. Тип события указывается при его создании.

Вызов Назначение

CreateEvent Создает событие или открывает уже существующее событие

OpenEvent Открывает существующее событие

SetEvent Устанавливает событие (переводит его в сигнальное состояние)

ResetEvent Сбрасывает событие

PulseEvent Переводит событие в сигнальное состояние на период времени, пока на это событие не прореагируют все ожидающие его потоки; после чего событие сбрасывается

Мьютекс

Мьютекс ( mutex , mutual exclusion — взаимное исключение). Поток может получить мьютекс в собственное владение. При этом другие потоки не смогут завладеть мьютексом до тех пор, пока первый поток не освободит его. Таким образом, в любой момент времени мьютекс может принадлежать только одному потоку, что исключает конфликты между потоками. Вместе с тем поток, являющийся владельцем мьютекса , может попытаться стать владельцем мьютекса повторно. Если поток присваивал себе мьютекс несколько раз, он обязан освободить его такое же количество раз и это расценивается как одно o бpaщение . Вызовы, предназначенные для работы с мьютексами , перечислены в таблице.

Мьютекс находится в сигнальном состоянии в случае, если он никому не принадлежит. Если мьютекс больше не нужен, вы можете освободить его при помощи вызова ReleaseMutex .

Вызов Предназначение

CreateMutex Создает новый мьютекс или открывает уже существующий

OpenMutex Открывает существующий мьютекс

ReleaseMutex Освобождает мьютекс и делает его доступным для других потоков

Семафор

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

Семафор находится в сигнальном состоянии, если его счетчик больше нуля. Чтобы освободить занятый вами ранее семафор, используйте вызов ReleaseSemaphore . При этом счетчик семафора будет увеличен на единицу.

Вызов Назначение

CreateSemaphore Создает новый семафор или открывает существующий

OpenSemaphore Открывает существующий семафор

ReleaseSemaphore Добавляет некоторое значение (обычно 1) к счетчику семафора, делая его доступным для большего количества потоков

Критические секции

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

Чтобы использовать критическую секцию, необходимо создать в глобальной памяти переменную CRITICAL_SECTION. После этого программа должна один раз обратиться к функции InitializeCriticalSection . В начале участка кода, доступ к которому требуется ограничить, необходимо разместить обращение к функции EnterCriticalSection . В конце критического участка кода следует разместить обращение к функции LeaveCriticalSection .

Блокированные переменные

Windows позволяет организовать работу программы таким образом, чтобы к некоторым переменным в любой момент времени мог обращаться только один поток. Для этого служат так называемые блокированные вызовы. Например, вызов InternetlockedIncrement.

Таймер синхронизации

Таймер синхронизации ( waitable timer ) является еще одним способом вызова функции АРС. Оповещение об изменении ( change notification ) — это специальный объект, который переходит в сигнальное состояние в случае, если содержимое дискового каталога изменяется. Чтобы создать оповещение об изменении, необходимо обратиться к функции F i ndFirstChangeNotification .

Варианты:

(Задание разрешается выполнять на языках С++ или С#)

Потоки синхронизировать с помощью мьютексов.

  1. В программе порождаются два потока работающие с одним файлом. Один поток пишет строки в файл, другой считает количество строк.

  2. Поиск файлов по содержимому в различных каталогах, количество потоков в два раза меньше каталогов.

  3. Вывод всех символов и их количество встречаемых в текстом файле.

  4. Сравнения файлов в нескольких каталогах несколькими потоками выводить процент схожести содержимого.

  5. Обеспечить замену символов из имен файлов в нескольких каталогах, каждый поток отвечает за свой символ.

  6. В программе порождаются два потока работающие с матрицей размером m*n. Один поток транспонирует матрицу, другой выводит сумму строк в транспонированной матрице.

  7. Реализовать программу по склейки одного файла из множества мелких, количество потоков в четыре раза меньше количества мелких файлов, каждый поток выводит статистику.

  8. Реализовать программу по созданию множества мелких файлов из одного большого, размер маленьких файлов произвольный, количество потоков равно 5.

  9. Поиск файлов по содержимому в различных каталогах, количество потоков в два раза меньше каталогов.

  10. В программе порождаются два потока работающие с матрицей размером m*n. Один поток считает сумму элементов в строках, другой сумму элементов столбцах.

Соседние файлы в папке 6 семестр