Цель: Программная реализация многопоточных приложений в операционной системе Windows.
Задачи:
1. Изучение теоретического материала по управлению потоками.
2. Составление алгоритма программы.
3. Программная реализация.
Ход работы:
1. Получить у преподавателя собственный вариант задания, который предусматривает распараллеливание работы на несколько потоков.
2. Используя изученные механизмы, разработать программу, реализующую полученное задание.
3. Написать отчет.
Ход защиты:
1. Продемонстрировать преподавателю программу, исполняющую несколько потоков.
2. Пояснить программный код приложения.
В современных ОС пользователям предлагается несколько типов параллельной работы, основными из которых являются процессы и потоки. Процессы – это программы на этапе выполнения. Потоки – это меньшая единица работы. Однако с точки зрения распределения ресурсов именно потоки являются главными, поскольку им, а не процессам предоставляется на определенное время центральный процессор для выполнения какой-либо работы. Рассмотрим несколько функций WinAPI, выполняющих некоторые операции над потоками.
|
|
Функция CreateThread создает поток, для выполнения внутри адресного пространства вызывающего процесса.
HANDLE CreateThread (
PSECURITY_ATTRIBUTES lpThreadAttributes,
// атрибуты защиты потока
DWORD dwStackSize, // начальный размер стека потока, в байтах
PTHREAD_START_ROUTINE lpStartAddress,
// указатель на функцию потока
PVOID lpParameter, // параметр для нового потока
DWORD dwCreationFlags, // флаги создание потока
PDWORD lpThreadId
//указатель на возвращаемый идентификатор потока
);
При успешном завершении функции возвращается дескриптор нового потока. При неудачном завершении функции возвращается NULL.
Параметры:
LpThreadAttributes – Указатель на структуру SECURITY_ATTRIBUTES, которая определяет, может ли возвращенный дескриптор быть унаследован дочерними процессами. Если lpThreadAttributes NULL, то дескриптор не может быть унаследован.
DwStackSize – Определяет размер, в байтах, стека для нового потока. Если определен 0, то размер стека по умолчанию равен размеру стека порождающего потока. Стек распределяется автоматически в пространстве памяти процесса, и освобождается при завершении потока.
LpStartAddress – Начальный адрес нового потока. Это обычно адрес функции, объявленной с соглашением о вызовах WINAPI, которое принимает одиночный 32-разрядный указатель как параметр и возвращает 32-разрядный код завершения. Прототип: DWORD WINAPI ThreadFunc (LPVOID);
LpParameter – Определяет единственное 32-разрядное значение параметра, передаваемое потоку.
DwCreationFlags – Определяет дополнительные флажки, которые управляют созданием потока. Если флажок определен CREATE_SUSPENDED, то поток создается в состоянии ожидания, и не будет выполняться, пока не будет вызвана функция ResumeThread. Если это значение нуль, то поток выполняется немедленно после создания.
|
|
LpThreadId – Указатель на 32-разрядную переменную, которая получает значение идентификатора потока
Поток можно завершить принудительно с помощью вызова следующих функций Win 32 API:
VOID ExitThread (
DWORD ExitCode);// код завершения потока
и
VOID TerminateThread (
HANDLE hThread, // поток, который требуется завершить
DWORD ExitCode // код завершения потока
);
Для примера приведен фрагмент программы, которая вычисляет произведение всех чисел от 1 до 100.
...
// Функция потока
DWORD WINAPI ThreadFuction (PVOID Parametr)
{ int proizv = 1; // результат произведения
int ii, *kk;
kk = (int *) Parametr;
for (ii = *k; ii < (*kk) + 50; ii ++) proizv *= ii;
return proizv;
}
...
// код вызовов функций для создания потоков
DWORD idThread;
int k1 = 1; k2 = 51;
HANDLE h1, h2;
// Создается два потока в приостановленном состоянии
h1 = CreateThread (NULL, 0, ThreadFunction, &k1, CREATE_SUSPENDED, &idThread);
h2 = CreateThread (NULL, 0, ThreadFunction, &k2, CREATE_SUSPENDED, &idThread);
// Выполнение потоков
ResumeThread (h1);
ResumeThread (h2);
...
В данном коде встретилась весьма полезная Win 32 API функция
ResumeThread, которая возобновляет выполнение приостановленного потока и описанная как
DWORD ResumeThread (
HANDLE hThread // поток, который требуется возобновить
);
Если вызов этой функции успешен, то возвращается предыдущее значение счетчика простоев данного потока, в противном случае – 0 xFFFFFFFF.
Выполнение отдельного потока можно приостанавливать несколько раз (точно такое же число раз он должен возобновляться), а производится это вызовом функции SuspendThread, описанная как
DWORD SuspendThread (
HANDLE hThread // поток, который требуется приостановить
);
Поток может сообщить ОС, чтобы она не выделяла ему процессор определенное время, указанное в миллисекундах.
VOID Sleep (DWORD MilliSeconds);
В ОС Windows 2000/ XP есть также функция, которая находит и открывает поток по идентификатору.
HANDLE OpenThread (
DWORD DesiredAccess,
BOOL InheritHandle,
DWORD dwThreadId
);