Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ОС 2012) Лабораторная работа 1.doc
Скачиваний:
6
Добавлен:
08.11.2019
Размер:
73.73 Кб
Скачать

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

Создание и завершение процессов и потоков. Приоритеты выполнения потоков.

Цель: Получить навыки в следующих предметных областях:

  • планирование и управление процессами и потоками;

  • потоки в многозадачных приложениях и ОС

  • распределение процессорного времени;

  • состояния процессов и потоков;

  • создание и завершение процессов и потоков;

  • приоритеты выполнения потоков.

Теоретические сведения

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

Все потоки процесса совместно используют свое виртуальное адресное пространство и системные ресурсы. Кроме того, каждый поток поддерживает обработчики особых ситуаций, приоритет диспетчеризации и набор структур, которые система будет использовать, чтобы сохранять контекст потока до тех пор, пока он не будет обслужен. Контекст потока (thread context) включает в себя набор машинных регистров потока, стек ядра, блок конфигурации потока и стек пользователя в адресном пространстве потока процесса.

Функция CreateProcess создает новый процесс, который запускается независимо от процесса, который его создал. Однако для простоты, это взаимоотношение упоминается как родительское - дочернее отношение.

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

void mainVOID )

{

STARTUPINFO si;

PROCESS_INFORMATION pi;

ZeroMemory&si, sizeof(si) );

si.cb = sizeof(si);

ZeroMemory( &pi, sizeof(pi) );

// Запустим дочерний процесс.

if( !CreateProcessNULL, // Нет имени модуля (используется командная строка).

"MyChildProcess",     // Командная строка.

NULL,                 // Дескриптор процесса не наследуемый.

NULL,                 // Дескриптор потока не наследуемый.

FALSE,                // Установим наследование дескриптора в FALSE.

0,                    // Флажков создания нет.

NULL,                 // Используйте блок конфигурации родителя.

NULL,                 // Используйте стартовый каталог родителя.

&si,                  // Указатель на структуру STARTUPINFO.

&pi )                 // Указатель на структуру PROCESS_INFORMATION.

)

ErrorExit( "CreateProcess failed." );

// Ждать до тех пор, пока дочерний процесс не выйдет из работы.

WaitForSingleObject( pi.hProcess, INFINITE );

// Закроем дескрипторы процесса и потока.

CloseHandle( pi.hProcess );

CloseHandle( pi.hThread );

}

Если CreateProcess завершается успешно, она возвращает структуру PROCESS_INFORMATION, содержащую дескрипторы и идентификаторы для нового процесса и первичного потока. Дескрипторы потока и процесса создаются с полными правами доступа, хотя доступ может быть ограничен, если Вы устанавливаете описатели системы безопасности. Когда Вы больше не нуждаетесь в этих дескрипторах, то закрываете их при помощи использования функции CloseHandle.

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

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

#include <windows.h>

#include <conio.h>

#include <stdio.h>

DWORD WINAPI ThreadFunc(LPVOID lpParam)

{

//setlocale(LC_CTYPE, "rus");

char *szMsg;

szMsg="Работает функция потока\n";

printf(szMsg);

MessageBoxA( NULL, szMsg, "Текущий процесс", MB_OK );

return 0;

}

VOID mainVOID )

{

DWORD dwThreadId, dwThrdParam = 1;

HANDLE hThread;

char *szMsg;

setlocale(LC_CTYPE, "rus");

hThread = CreateThread(

NULL,         // атрибуты безопасности по умолчанию

0,            // размер стека используется по умолчанию

ThreadFunc,   // функция потока

&dwThrdParam, // аргумент функции потока

0,            // флажки создания используются по умолчанию

&dwThreadId); // возвращает идентификатор потока

// При успешном завершении проверяет возвращаемое значение.

if (hThread == NULL)

{

szMsg="Поток не запущен!\n";

MessageBoxA( NULL, szMsg, "Текущий процесс", MB_OK );

}

else

{

szMsg="Поток завершился! Закройте окно и нажмите клавишу ...\n";

printf(szMsg);

MessageBoxA( NULL, szMsg, "Текущий процесс", MB_OK );

_getch();

CloseHandle( hThread );

}

}

Для простоты, этот пример передает указатель на значение как на параметр функции потока. Это может быть указатель на любой тип данных или структуру, или это может быть пропущено совсем, при помощи передачи указателя NULL и удаления ссылок на параметр в ThreadFunc.

Создающий поток может использовать параметры функции CreateThread, чтобы определить нижеследующее:

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

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

- Флажок создания, который разрешает Вам создать поток в состоянии ожидания. Когда произошла приостановка, поток не запускается до тех пор, пока не будет вызвана функция ResumeThread.

Поток исполняется до тех пор, пока не произойдет одно из нижеследующих событий:

- Поток вызывает функцию ExitThread.

- Какой-либо поток процесса вызывает функцию ExitProcess.

- Функция возвращает значение потока.

- Какой-либо поток вызывает функцию TerminateThread с дескриптором потока.

- Какой-либо поток вызывает функцию TerminateProcess с дескриптором процесса.

Функции TerminateThread и TerminateProcess должны быть использованы только в экстремальных случаях, поскольку они не дают потокам возможности очиститься, не уведомляют связанные DLL и не освобождают начальный стек.

Функция GetExitCodeThread возвращает значение состояния завершения потока. В то время как поток исполняет код, его состоянием завершения работы является STILL_ACTIVE. Когда поток заканчивает работу, он свое состояние завершения изменяет с STILL_ACTIVE на код выхода из потока. Код выхода является или значением, определяемым при вызове ExitThread, ExitProcess, TerminateThread илиTerminateProcess, или значением, возвращенным функцией потока.

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