«Если отладка - процесс удаления ошибок, то программирование должно быть процессом их внесения»
38. Приложения, процессы и потоки
Приложение – самодостаточный набор машинных инструкций, обеспечивающий решение конкретной задачи.
Процесс обычно определяют как экземпляр (или копию) выполняемой программы (приложения). В Win32 процессу отводится 4Гбайта адресного пространства. В этом адресном пространстве расположен exe-файл, код и данные DLL-библиотек. Кроме того, процессу принадлежат такие ресурсы, как файлы, динамические области памяти и потоки (thread). Ресурсы, которые создаются при жизни процесса, обязательно уничтожаются при его завершении.
В MSDN процесс определяется как контекст безопасности, в котором выполняется приложение. Обычно контекст безопасности связан с пользователем и приложения получают его уровень полномочий. (The security context under which an application runs. Typically, the security context is associated with a user, so all applications running under a given process take on the permissions and privileges of the owning user.)
Для того чтобы процесс что-либо выполнял, в нем обязательно должен быть хоят бы один поток. Поток можно определить как такой фрагмент программного кода, который выполняется последовательно. Именно потоки отвечают за исполнение программного кода, помещенного в адресное пространство процесса. При создании процесса в Win32 первый (первичный – primary) поток создается системой автоматически. Далее этот поток может порождать другие потоки, которые в свою очередь могут порождать третьи и т.д. Таким образом, процесс может включать произвольное число потоков, которые можно создавать и уничтожать. Процесс завершается, когда завершается выполнение первичного потока.
Приоритеты процессов и потоков. Операционная система распределяет процессорное время между потоками, выделяя каждому из них определенную долю времени (квант). Процессорное время выделяется по очереди каждому потоку, но при этом учитывается также приоритет потока. Когда прекращается выполнение первичного потока процесса, уничтожается и сам процесс.
Многопоточные процессы организуются в тех случаях, когда требуется:
Ø избежать "узких" мест. Например, если процесс ожидает завершения файловой операции, связи с другим компьютером или просто вывода на экран какого-либо сложного изображения, то он попросту простаивает. В этом случае можно организовать отдельный поток или потоки, которые будут выполнять код параллельно;
Ø повысить скорость функционирования процесса в целом за счет того, что некритическая часть кода выполняется потоками с более низким приоритетом;
Ø использовать на полную мощь многопроцессорный компьютер. В этом случае каждый поток может исполняться на отдельном процессоре.
Интерфейс Win32 API позволяет управлять созданием и уничтожением потоков, распределением времени между потоками и приоритетами процессов и потоков. Процессы могут иметь классы приоритетов, приведенные в табл.
Классы приоритетов процессов
Приоритет |
Смысл |
ABOVE_NORMAL_PRIORITY_CLASS |
Больше NORMAL_PRIORITY_CLASS, но ниже HIGH_PRIORITY_CLASS. |
BELOW_NORMAL_PRIORITY_CLASS |
Больше IDLE_PRIORITY_CLASS, но ниже NORMAL_PRIORITY_CLASS. |
HIGH_PRIORITY_CLASS |
Высший приоритет. Такой приоритет имеет, например, диспетчер задач Windows |
IDLE_PRIORITY_CLASS |
Низший приоритет (фоновый процесс). Такой процесс получит время только в том случае, если в системе нет других исполняемых потоков. Типичный пример – программа заставка. |
NORMAL_PRIORITY_CLASS |
Нормальный приоритет. Абсолютное большинство процессов, в том числе системных, имеют этот приоритет. |
REALTIME_PRIORITY_CLASS |
Самый высокий (реального времени) приоритет. Потоки этого процесса вытесняют все другие. Этот приоритет надо использовать с большой осторожностью и только на короткое время. К примеру, выполнение процесса с таким приоритетом «остановит» мышь или кеширование дисковых операций |
Функция Win API SetPriorityClass позволяет изменить приоритет процесса на этапе выполнения приложения:
BOOL SetPriorityClass(
HANDLE hProcess, // дескриптор процесса
DWORD dwPriorityClass // класс приоритета
);
Класс реального времени используется только для процессов, которые, например, обрабатывают высокоскоростные потоки данных и завершаются за короткое время. Так как процесс реального времени имеет приоритет более высокий, чем большинство процессов ОС, то неаккуратное его использование может привести к зависанию системы.
Класс с высоким приоритетом также используется достаточно редко. Например, он может понадобиться в случае связи с каким-либо внешним устройством, которое, если не получит сигнал в течение короткого времени, отключается.
Большинство процессов выполняется с нормальным приоритетом. Это означает, что процесс не требует какого-либо повышенного внимания со стороны ОС.
Процессы с фоновым приоритетом получают время только в том случае, если у диспетчера задач нет других процессов. Примеры таких процессов – это программы-заставки, автосохранение или реорганизация данных и т.п.
Интерфейс Win32 API предлагает всего 32 уровня приоритета с номерами 0..31. Windows распределяет процессорное время между потоками в соответствии с их приоритетом, а не приоритетом процессов. (Процесс в Windows считается инертным, т.е. сам по себе он ничего не выполняет, а имеет смысл только при наличии в нем хотя бы одного потока.) При создании нового потока ему назначается такой же приоритет, как и у породившего его процесса. Вместе с тем приоритет потока можно изменять (свойство TThread.Priority в Delphi или функция Win API SetThreadPriority) при его создании или в процессе выполнения:
BOOL SetThreadPriority( HANDLE hThread, // дескриптор потока int nPriority // приоритет потока);Приоритет |
Смысл |
THREAD_PRIORITY_ABOVE_NORMAL |
На 1 выше приоритета процесса |
THREAD_PRIORITY_BELOW_NORMAL |
На 1 ниже приоритета процесса |
THREAD_PRIORITY_HIGHEST |
На 2 выше приоритета процесса |
THREAD_PRIORITY_IDLE |
Приоритет 1 для классов приоритета процесса IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS или HIGH_PRIORITY_CLASS. Приоритет 16 для REALTIME_PRIORITY_CLASS. |
THREAD_PRIORITY_LOWEST |
На 2 ниже приоритета процесса |
THREAD_PRIORITY_NORMAL |
Приоритет потока совпадает с приоритетом процесса |
THREAD_PRIORITY_TIME_CRITICAL |
Приоритет 15 для классов приоритета процесса IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS или HIGH_PRIORITY_CLASS. Приоритет 31 для REALTIME_PRIORITY_CLASS |
Примечание к табл. Для Windows 2000/XP параметр nPriority может принимать также значения - 7, - 6, -5, - 4, - 3, 3, 4, 5 или 6. За дополнительной информацией обращайтесь к разделу Scheduling Priorities в справочной системе MSDN.
В Delphi этот приоритет может принимать одно из значений, приведенных в таблице.
Приоритет |
Значение |
tpIdle |
Низший приоритет. Поток получает время только в том случае, когда система бездействует, т.е. в ней не выполняются никакие другие потоки. Windows не прерывает выполнение других потоков для потоков, чтобы предоставить время потоку с этим приоритетом |
tpLowest |
На две единицы меньше нормального |
tpLower |
На одну единицу меньше нормального |
tpNormal |
Нормальный приоритет, равный приоритету процесса |
tpHigher |
На одну единицу выше нормального |
tpHighest |
На две единицы выше нормального |
tpTimeCritical |
Наивысший приоритет. Следует применять с осторожностью для того, чтобы не "повесить" весь процесс или систему |
Простой пример использования потоков содержится в проекте ..\Demos\Threads, где реализованы три различных метода сортировки массивов, исполняемых тремя потоками. Еще один пример использования потоков находится в каталоге ..Help\Examples\PrgrsBar.
В двух проектах ..\Demos\IPCDemos приведен достаточно сложный пример, иллюстрирующий взаимодействие между процессами. В этом примере демонстрируется использование таких возможностей Win32 API и Delphi, как:
Ø взаимодействие процессов (Interprocess Communication);
Ø потоки (Threads);
Ø события (Events);
Ø объекты "взаимное исключение" (Mutex);
Ø разделяемая память (Shared Memory);
Ø контроль выполнения одного экземпляра приложения (Single instance exe).
В заключение отметим, что любой процесс может породить дочерний процесс с помощью функции Win32 API CreateProcess.
Получение и модификация приоритетов процесса и потока.
unit Unit1;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
public
H,T : THandle;
end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if not SetPriorityClass(H,IDLE_PRIORITY_CLASS) then
begin
Memo1.Lines.Add('Ошибка при вызове SetPriorityClass');
Exit;
end;
if not SetThreadPriority(T,THREAD_PRIORITY_BELOW_NORMAL) then
begin
Memo1.Lines.Add('Ошибка при вызове SetThreadPriority');
Exit;
end;
Memo1.Lines.Add('Process priority='+IntToStr(GetPriorityClass(H)));
Memo1.Lines.Add('Thread priority='+IntToStr(GetThreadPriority(T)));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
H:=GetCurrentProcess;
T:=GetCurrentThread;
Memo1.Clear;
Memo1.Lines.Add('Process priority='+IntToStr(GetPriorityClass(H)));
Memo1.Lines.Add('Thread priority='+IntToStr(GetThreadPriority(T)));
end;
END.
«37. Платформы семейства Windows»
39. Класс TThread