Text
                    Лабораторная работа №
3
. Потоки в Windows (2 ч.)
Потоки
. Создание и завершение пот
о
ков.
Приостановка и
возобновление потоков. Многопоточные приложения.
Потоком
управления
(
thread
)
наз
ывает
ся
последовательность инструкций
программы, выполняемая
процессором. Иногда
для этого
используется термин нить.
Программа, использующая одновременно несколько
потоков управления называется
многопоточной
.
Просмотреть количество потоков, запущенных
прил
ожением можно при помощи стандартного «Диспетчера
задач» Windows.
Более подробную информацию можно получить,
например, при помощи Sysinternals Process Explorer. Он
отображает не только количество потоков, но и позволяет
увидеть их TID, адреса функций, ко
торые в них выполняются,
состояние, а также приостановить, возобновить или завершить
отдельные потоки.


Содержимое памяти, к которому имеет доступ поток, называется контекстом потока . По отношению к обрабатываемым данным , выполняемые в потоках функции дел ятся на потокобезопасные и потоконебезопасные . Потокобезопасные функции независимо от количества параллельных вызовов корректно изменяют используемые данные и блокируют доступ к ресурсам, которые они используют на время их использования. В Windows потоком называется объект ядра, которому ОС выделяет процессорное время для выполнения программы. Каждый поток в Windows имеет собственный дескриптор и уникальный идентификатор (аналогично ProcessID у процессов). Для создания потока используется функция CreateThre ad со следующим прототипом : HANDLE CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, 
LPDWORD lpThreadId ); В случае успешного завершен ия функция возвращает дескриптор созданного потока или NULL в случае ошибки. Параметр dwStackSize задает размер стека потока, значение 0 означает, что система самостоятельно выделяет под стек блок памяти минимального размера. Параметр lpStartAddress указыв ает на исполняемую в поток е функцию. Такая функция должна быть описана согласно следующему прототипу: DWORD WINAPI имя_функции_потока ( LPVOID lpParameter ); Например: DWORD WINAPI MyThreadFunction (LPVOID myParam); Параметр lpParameter – это передаваемы й в функцию потока параметр, который является указателем на тип void. Параметр dwCreationFlags определяет начальное состояние созданного потока: 0 – функция потока начинает выполняться сразу после создания потока; CREATE_SUSPENDED – поток создается в приос тановленном состоянии. Для его запуска нужно использовать функцию ResumeThread . Выходной параметр lpThreadId указывает на переменную, в которую Windows поместит идентификатор созданного потока. Допускается его установка в NULL , тогда Windows не будет возвр ащать идентификатор потока. Пример простейшей программы, создающей несколько потоков исполнения: #include <windows.h> #include <iostream> using namespace std; DWORD WINAPI WorkerThread(LPVOID param) { while( true ) { cout << *(( int *)param) << " "; } } 
int main() { HANDLE hThread; DWORD ThreadID; DWORD Num = 2; hThread = CreateThread(NULL, 0, WorkerThread, ( void *)&Num, 0, &ThreadID); if(hThread == NULL) { cout << " ошибка " << GetLastError() << endl; system( "pause" ); return - 1; } while( tru e ) { cout << 1 << " "; } return 0; } Задание 1. На основе приведенных выше материалов с оздайте в Microsoft Visual Studio консольное приложение с 2 - 3 потоками исполнения. Соберите проект и проверьте с помощью Диспетчера задач Windows , что потоки успеш но запущены. Для выхода из потока он может использ ова т ь вызов оператора return или функции ExitThread со следующим прототипом: VOID ExitThread( DWORD dwExitCode ); Кроме того, один поток может завершить другой поток с помощью вызова функции TerminateThr ead : BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode ); Кроме завершения, поток может быть приостановлен на некоторое время с помощью функции SuspendThread : DWORD SuspendThread( HANDLE hThread ); 
Для возобновления остановленного таким образом потока используется функция ResumeThread : DWORD ResumeThread( HANDLE hThread ); Задание 2. Разработайте приложение, которое будет запускать дополнительный поток исполнения, в котором проигрывать какую - либо мелодию с помощ ью функции Beep() . Основной поток должен принимать команды пользователя и в соответствии с ними приостанавливать и ли возобновлять работу потока, проигрывающего звук. Отследите с помощью Process Explorer’а состояние контролируемого потока. Функция Beep генерирует тон заданной частоты и во спроизводит его через PC - спикер (при его наличии) . Функция является синхронной, поэтому её вызов лучше выполнять в отдельном потоке. Прототип функции: BOOL WINAPI Beep( DWORD dwFreq, DWORD dwDuration ); dwFreq – частота звука в герцах (может принимать значения от 37 до 32767 ; ноте «ля» первой октавы соответствует 440 Hz, разница между двумя соседними нотами ~ 50 Hz); dwDuration – длительность звука в секундах. Поток может сам приостановить свое выполнение с помощью функции Sleep: VOID Sleep( DWORD dwMill iseconds ); Здесь параметр dwMilliseconds задает интервал, на который приостанавливается выполнение потока. В случае задания константы INFINITE поток будет приостановлен на всегда, в случае задания значения 0 – поток просто завершит свое выполнение на текущ ий выделенный ему квант процессорного времени. Задание 3 . Разработайте приложение, вычисляющее сумму элементов целочисленной матрицы N x N . Для того, чтобы получить преимущество при выполнении на многопроцессорной системе или на многоядерном процессоре п р ограмма должна выполнять работу с помощью N потоков 
выполняющихся параллельно (ближайшей аналогией будет бригада строителей, строящих одну и ту же стену).