Лабораторная работа

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

Категория:

Лабораторная работа

Дисциплина:

Системное программирование

Город:

Беларусь, Минск

Учебное заведение:

БНТУ, ФИТР

Тег:

#Системное_программирование

Стоимость работы:

13 руб.

Оценка: 10
Объем страниц: 7
Год сдачи: 2022
Дата публикации: 14.06.2022

* Кроме файла с работой, также есть архив с дополнительными файлами.

Описание дополнительных файлов:

Папка LR9 — содержит исходный код программы на языке C++

Фрагменты для ознакомления

УПРАВЛЕНИЕ ПОТОКАМИ В WINDOWS

Вариант 06

Цель работы: 

изучить основы создания и управления потоками в ОС Windows.

 

Изучаемые вопросы

 

  1. Виды потоков, состояния потока.
  2. Структура CONTEXT.
  3. Создание потока.
  4. Относительный приоритет потока.
  5. Потоковая функция.
  6. Функции WinAPI для управления потоками.
  7. Окончание потока.
  8. Время выполнения потока.

 

Постановка задачи

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

 

Ход работы

 

1.    Виды потоков, состояния потока.

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

Многопоточная модель охватывает 2 категории потоков и их комбинацию:

  • потоки на уровне пользователя ULT (User Level Thread);
  • потоки на уровне ядра KLT (Kernel Level Thread);
  • комбинированная модель UKLT.

ULT управляются самим приложением. KLT управляется самим ядром через интерфейс прикладного программирования средств ядра ОС.

 

 

2.    Структура CONTEXT.

У каждого потока собственный набор регистров процессора, называемый контекстом потока. Эта структура с именем CONTEXT отражает состояние регистров процессора на момент последнего исполнения потока.

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

Получить сведения о текущем состоянии регистров процессора. можно с помощью функции:

  BOOL GetThreadContext( HANDLE hThread, PCONTEXT pContext);

 

Описание структуры CONTEXT:

typedef struct _CONTEXT {
DWORD ContextFlags;
DWORD   Dr0;            DWORD   Dr1;
DWORD   Dr2;            DWORD   Dr3;
DWORD   Dr6;            DWORD   Dr7;
DWORD   SegGs;        DWORD   SegFs;
DWORD   SegEs;        DWORD   SegDs;
DWORD   Edi; DWORD   Esi;
DWORD   Ebx;            DWORD   Edx;
DWORD   Ecx;            DWORD   Eax;
DWORD   Ebp;            DWORD   EFlags;
DWORD   Esp; DWORD   SegSs;
BYTE  ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;

 

Пример использования функции GetThreadContext:

BOOL GetContext(HANDLE hThread, HWND hList, int ThreadNumber)
{
       CONTEXT ct;

       ct.ContextFlags = (CONTEXT_FULL);

       if(!GetThreadContext(tiThreads[CheckRadio].hThread, &ct))
       {
             return FALSE;
       }

       TCHAR buff[1024];

       SendMessage(hList, LB_RESETCONTENT, NULL, NULL);

       swprintf_s(buff, L"КОНТЕКСТ %d-ГО ПОТОКА", ThreadNumber);
       SendMessage(hList, LB_INSERTSTRING, 0, (LPARAM)buff); 

       swprintf_s(buff, L"EAX:  0x%X", ct.Eax);
       SendMessage(hList, LB_INSERTSTRING, 1, (LPARAM)buff); 

       swprintf_s(buff, L"EBX:  0x%X", ct.Ebx);
       SendMessage(hList, LB_INSERTSTRING, 2, (LPARAM)buff); 

       swprintf_s(buff, L"ECX:  0x%X", ct.Ecx);
       SendMessage(hList, LB_INSERTSTRING, 3, (LPARAM)buff); 

       swprintf_s(buff, L"EDX:  0x%X", ct.Edx);
       SendMessage(hList, LB_INSERTSTRING, 4, (LPARAM)buff); 

       swprintf_s(buff, L"EBP:  0x%X", ct.Ebp);
       SendMessage(hList, LB_INSERTSTRING, 5, (LPARAM)buff); 

       swprintf_s(buff, L"EDI:  0x%X", ct.Edi);
       SendMessage(hList, LB_INSERTSTRING, 6, (LPARAM)buff); 

       swprintf_s(buff, L"EIP:  0x%X", ct.Eip);
       SendMessage(hList, LB_INSERTSTRING, 7, (LPARAM)buff); 

       swprintf_s(buff, L"ESI:  0x%X", ct.Esi);
       SendMessage(hList, LB_INSERTSTRING, 8, (LPARAM)buff); 

       swprintf_s(buff, L"ESP:  0x%X", ct.Esp);
       SendMessage(hList, LB_INSERTSTRING, 9, (LPARAM)buff); 

       swprintf_s(buff, L"SeqCs:  0x%X", ct.SegCs);
       SendMessage(hList, LB_INSERTSTRING, 10, (LPARAM)buff); 

       swprintf_s(buff, L"SeqDs:  0x%X", ct.SegDs);
       SendMessage(hList, LB_INSERTSTRING, 11, (LPARAM)buff);

       swprintf_s(buff, L"SeqEs:  0x%X", ct.SegEs);
       SendMessage(hList, LB_INSERTSTRING, 12, (LPARAM)buff); 

       swprintf_s(buff, L"SeqFs:  0x%X", ct.SegFs);
       SendMessage(hList, LB_INSERTSTRING, 13, (LPARAM)buff); 

       swprintf_s(buff, L"SeqGs:  0x%X", ct.SegGs);
       SendMessage(hList, LB_INSERTSTRING, 14, (LPARAM)buff); 

       swprintf_s(buff, L"SeqSs:  0x%X", ct.SegSs);
       SendMessage(hList, LB_INSERTSTRING, 15, (LPARAM)buff); 

       return TRUE;
}

Результат выполнения кода на рисунке 1.

       

Заполнение структуры CONTEXT

Рисунок 1 – Заполнение структуры CONTEXT

3.    Создание потока.

Для создания нового потока используется функция CreateThread:

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES Ipsa;
DWORD cbStack;
LPTHREAD_START_ROUTINE IpStartAddr;
LPVOID IpvThreadParm;
DWORD fdwCreate;
LPDWORD IpIDThread);

При каждом вызове этой функции система:

1. Создаёт объект ядра «поток» для идентификации и управления «новорожденным» потоком. В нем хранится большая часть системной информации, необходимой для управления потоком. Описатель этого объекта — значение, возвращаемое функцией CreateThread.

2. Инициализирует код завершения потока (регистрируемый в объекте ядра «поток») идентификатором STILL_ACTIVE и присваивает счетчику простоя потока (thread's suspend count) единицу. Последний тоже запоминается в объекте ядра «поток».

3. Создаёт для нового потока структуру CONTEXT.

4. Формирует стек потока, для чего резервирует в адресном пространстве регион, передает ему 2 страницы физической памяти и присваивает им атрибут защиты PAGE_READWRITE> а второй странице (если считать снизу вверх) дополнительно устанавливает атрибут PAGE_GUARD. Подробнее о стеке потока см. главу 7.

5. Значения IpStartAddr и IpvThreadParm помещаются в самый верх стека — так, чтобы представить их параметрами, передаваемыми в StartOfThread.

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

Ниже приведён фрагмент кода, демонстрирующий создание потока в риостановленном состоянии.

tiThreads[CheckRadio].hThread =  CreateThread(NULL, 0,
tiThreads[CheckRadio].tsrThreadFunc, &tiThreads[CheckRadio], CREATE_SUSPENDED, &tiThreads[CheckRadio].dwThreadId);

 

4.    Относительный приоритет потока.

При создании потока функцией CreateThread() существует возможность задать относительный приоритет потока. Если не указывать данный флаг, то по умолчанию потоку присвоится нормальный приоритет. Возможные приоритеты перечислены в таблице 1.1. Также задать приоритет потока можно с помощью функции SetThreadPriority:

BOOL SetThreadPriority(HANDLE hThread, int nPriority);

Ниже приведён пример использования функции SetThreadPriority:

if(tiThreads[CheckRadio].hThread != NULL)
{
       int priority;

       switch ((BYTE)SendDlgItemMessage(hDlg, IDC_COMBO1, CB_GETCURSEL, NULL, 0L))
       {
             case 0:
             {
                    priority = THREAD_PRIORITY_BELOW_NORMAL;
                    break;
             }
             case 1:
             {
                    priority = THREAD_PRIORITY_NORMAL;
                    break;
             }
             case 2:
             {
                    priority = THREAD_PRIORITY_ABOVE_NORMAL;
                    break;
             }
             case 3:
             {
                    priority = THREAD_PRIORITY_HIGHEST;
                    break;
             }
             case 4:
             {
                    priority = THREAD_PRIORITY_TIME_CRITICAL;
                    break;
             }
             case 5:
             {
                    priority = THREAD_PRIORITY_LOWEST;
                    break;
             }
             case 6:
             {
                    priority = THREAD_PRIORITY_IDLE;
                    break;
             }
             default:
                    return (INT_PTR)TRUE;
       }
}

                                                      SetThreadPriority(tiThreads[CheckRadio].hThread, priority);
                                      }

Таблица 1.1

Относительные приоритеты потоков

Приоритет

Флаговый идентификатор

Below normal (ниже обычного)

THREAD_PRIORITY_BELOW_NORMAL

Normal (обычный)

THREAD_PRIORITY_NORMAL

Above normal (выше обычного)

THREAD_PRIORITY_ABOVE_NORMAL

Highest (высокий)

THREAD_PRIORITY_HIGHEST

Realtime (реального времени)

THREAD_PRIORITY_TIME_CRITICAL

Lowest (низкий)

THREAD_PRIORITY_LOWEST

Idle (простаивающий)

THREAD_PRIORITY_IDLE

5.    Потоковая функция.

6.    Функции WinAPI для управления потоками.

7.    Окончание потока.

8.    Время выполнения потока.

Результаты работы программного обеспечения

На рисунке 2 приведены результаты работы программы.            

Рисунок 2- Результаты работы программ

Выводы:

1.   Для создания нового потока используется функция CreateThread.

2. У каждого потока собственный набор регистров процессора, называемый контекстом потока. Эта структура с именем CONTEXT отражает состояние регистров процессора на момент последнего исполнения потока.

3. Поток завершается при исполнение всего кода потоковой функции или при вызове функции ExitThread, TerminateThread или при завершении процесса.

 

Используемые источники:

  1. Системное программирование: лабораторный практикум для студентов специальностей 1-40 01 02 «Информационные системы и технологии» и 1-40 01 01 «Программное обеспечение информационных технологий» / сост. Н.А. Разорёнов. – Минск: БНТУ, 2012. – 81 с.
  2. http://msdn.microsoft.com
  3. Рихтер
18