Лекції з WinApi

Тема №2 Багатозадачність

2. Багатозадачність
 2.1. Процеси і потоки

Процес - завантажена в пам'ять і готова до виконання програма.

Кожен процес має свій власний віртуальний адресний простір (4Gb). Процес складається з коду, даних і інших системних ресурсів, таких як відкриті файли, канали (pipes), що синхронізують об'єкти.

Потік (thread) - базовий об'єкт, якому операційна система розподіляє час центрального процесора.

Виконання процесу починається зі стартового потоку. Надалі він може породжувати інші потоки. Ресурси процесу доступні всім його потокам. Кожен потік використовує структуру даних, для збереженняконтексту виконання, у той час, коли в нього віднімається процесор. У контекст входять регістри процесора, перемінні оточення, стеки ядра і користувача. Усі потоки одного процесу спільно використовують його віртуальний адресний простір.

Процесорний час розподіляється по черзі між потоками, а не між процесами. Тривалість кванта виділення часу складає близько 20 мс.

2. Багатозадачність.
 2.2. Розподіл часу між потоками

Процесорний час виділяється потокам відповідно до їхнього рівня пріоритету. Потоку з більш низьким пріоритетом не виділяється час, якщо на нього претендує потік з більш високим рівнем пріоритету. Більш того, процес з більш низьким пріоритетом переривається до витікання кванта часу, якщо на процесор претендує потік з більш високим рівнем пріоритету. Необхідно пам'ятати, що в середовищі Windows основна “робота” потоку складається в чеканні події і реагуванні на нього. Це дає шанс на виконання потокам з низьким рівнем пріоритету.

Рівні пріоритетів варіюються в діапазоні від 0 (нижчий) до 31 (вищий).

Рівень пріоритету кожного потоку складається з трьох складових

  • клас пріоритету процесу (простоючий, нормальний, високий, реального часу)
  • рівень пріоритету потоку усередині класу пріоритету процесу (нижній, нижче нормального, нормальний, вище нормального, вищий)
  • динамічно встановлений рівень пріоритету.
    1. Клас пріоритету процесу

Клас

Прапор у функції CreateProcess

Числовий рівень

Idle (простоючий)

IDLE_PRIORITY_CLASS

4

Normal (нормальний)

NORMAL_PRIORITY_CLASS

7-9

High (високий)

HIGH_PRIORITY_CLASS

13

Real time(реального часу)

REALTIME_PRIORITY_CLASS

24

2.                                                        При запуску на виконання процесу йому призначається один з чотирьох класів пріоритету. Рівень Idle призначається процесу, що нічого не повинний робити у випадку активності інших процесів (наприклад, хоронитель екрана). Процесам, що запускається користувачем, привласнюється нормальний рівень. Користувач може запустити кілька процесів. Томові процесу, з яким користувач безпосередньо працює (а це може бути тільки один процес) рівень пріоритету піднімається на двох одиниць (7+2 = 9). Це робить спілкування з прикладною програмою більш “комфортабельним”. Високий клас пріоритету призначається деяким системним процесам, що простоюють до виникнення визначених подій і, тому, не заважають іншим процесам. Тільки в особливих випадках процес може відноситися до класу Real time.

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

Ідентифікатор

Рівень пріоритету потоку

THREAD_PRIORITY_LOWEST

На 2 нижче рівні класу

THREAD_PRIORITY_BELOW_NORMAL

На 1 нижче рівня класу

THREAD_PRIORITY_NORMAL

Дорівнює рівню класу

THREAD_PRIORITY_ABOVE_NORMAL

На 1 вище рівня класу

THREAD_PRIORITY_HIGHEST

На 2 вище рівні класу

THREAD_PRIORITY_IDLE

Дорівнює 1 для процесів класу IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, і HIGH_PRIORITY_CLASS і дорівнює 16 для REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

Дорівнює 15 для процесів класу IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, і HIGH_PRIORITY_CLASS, і дорівнює 31 для REALTIME_PRIORITY_CLASS

      1. Динамічна зміна рівня пріоритету потоку

Клас пріоритету процесу і рівень пріоритету потоку усередині класу визначають базовий рівень пріоритету потоку. Цей рівень може динамічно змінюватися системою, а саме, підвищуватися на 2 одиниці у відповідь на надходження повідомлень у чергу потоку з наступним зниженням до базового рівня після закінчення визначеного проміжку часу. Це правило діє тільки для потоків до 15 рівня.

2. Багатозадачність.
 2.3. Робота з процесами і потоками в Win32® API.

·  Список функцій

У Win32® API визначені наступні функції роботи з процесами і потоками

Назва функції

Виконувана дія

AttachThreadInput

Переключення механізмів уведення з однієї нитки на іншу

CommandLineToArgv

Робить розбір командного рядка в Unicode

CreateProcess

Створює процес

CreateRemoteThread

Створює потік в адресному просторі іншого процесу

CreateThread

Створює потік

ExitProcess

Завершує процес і весь його потоки

ExitThread

Завершує потік

FreeEnvironmentStrings

Звільняє пам'ять області перемінні середовища

GetCommandLine

Повертає покажчик на командний рядок

GetCurrentProcess

Повертає описувач (handle) поточного процесу

GetCurrentProcessId

Повертає ідентифікатор поточного процесу

GetCurrentThread

Повертає описувач (handle) поточного потоку

GetCurrentThreadId

Повертає ідентифікатор поточного потоку

GetEnvironmentStrings

Повертає рядок перемінні середовища

GetEnvironmentVariable

Повертає значення зазначеного перемінного середовища

GetExitCodeProcess

Повертає код завершення процесу

GetExitCodeThread

Повертає код завершення потоку

GetPriorityClass

Повертає клас пріоритету процесу

GetProcessAffinityMask

Повідомляє, на яких процесорах дозволене виконання процесу

GetProcessShutdownParameters

Повідомляє параметри поводження процесу при завершенні роботи системи

GetProcessTimes

Повертає тимчасові характеристики зазначеного процесу

GetProcessVersion

Повідомляє версію Windows, для якої призначений процес

GetProcessWorkingSetSize

Повертає характеристики доступного процесу адресного простору

GetStartupInfo

Повертає параметри процесу, отримані їм при створенні

GetThreadPriority

Повідомляє пріоритет зазначеного потоку

GetThreadTimes

Повертає тимчасові характеристики зазначеного потоку

OpenProcess

Повертає описувач (handle) зазначеного процесу

ResumeThread

Зменшує лічильник затримок потоку (чи запускає його)

SetEnvironmentVariable

Установлює значення зазначеного перемінного середовища

SetPriorityClass

Установлює клас пріоритету процесу

SetProcessShutdownParameters

Установлює параметри поводження процесу при завершенні роботи системи

SetThreadAffinityMask

Установлює, на яких процесорах дозволене виконання потоку

SetThreadPriority

Установлює пріоритет зазначеного потоку

Sleep

Затримує виконання потоку на зазначену кількість мілісекунд

SleepEx

Затримує виконання до настання події введення/ чивисновку на час

SetProcessWorkingSetSize

Установлює характеристики доступного процесу адресного простору

SuspendThread

Припиняє виконання зазначеного потоку

TerminateProcess

Завершує зазначений процес

TerminateThread

Завершує зазначений потік

TlsAlloc

Розподіляє індекс локальної пам'яті потоку (thread local storage TLS)

TlsFree

Звільняє індекс TLS

TlsGetValue

Повертає дані, розміщені в TLS із зазначеним індексом

TlsSetValue

Поміщає дані в TLS із зазначеним індексом

WaitForInputIdle

Чекає, поки не почнеться введення для зазначеного процесу

WinExec

Виконує зазначений додаток

Докладний опис функцій приведений у Win32® Programmer’s Reference. Тут будуть докладно розглянуті тільки деякі функції.

·  Функція CreateProcess()

Створює новий процес і його первинний потік. Новий процес виконує зазначений файл, що виконується.

Формат функції:

BOOL CreateProcess(

LPCTSTR lpApplicationName, // ім'я файлу, що виконується

LPTSTR lpCommandLine, // командний рядок

LPSECURITY_ATTRIBUTES lpProcessAttributes, // атрибути захисту процесу

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибути захисту

// потоку

BOOL bInheritHandles, // прапор спадкування описувачей

DWORD dwCreationFlags, // прапори створення

LPVOID lpEnvironment, // покажчик блоку перемінні середовища

LPCTSTR lpCurrentDirectory, // поточний каталог

LPSTARTUPINFO lpStartupInfo, // блок початкових параметрів

LPPROCESS_INFORMATION lpProcessInformation // покажчик

// структури, що описує породжений // процес

);

Функція повертає TRUE у випадку успіху і FALSE - у випадку невдачі.

Параметри:

lpApplicationName - покажчик на рядок, що містить ім'я програми, що виконується. Ім'я може бути повне. Якщо воно не повне, то пошук файлу виробляється в поточному каталозі. Параметру може бути привласнене значення NULL. У цьому випадку як ім'я файлу виступає перша виділена пробілами лексема з рядка lpCommandLine;

lpCommandLine - покажчик командного рядка. Якщо параметр lpApplicationName має значення NULL, то ім'я файлу, що виконується, виділяється з lpCommandLine, а пошук файлу, що виконується, виробляється відповідно до правил, що діють у системі;

lpProcessAttributes - покажчик на структуру, що описує параметри захисту процесу. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

lpThreadAttributes- покажчик на структуру, що описує параметри захисту первинного потоку. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

bInheritHandles - визначає, чи буде породжений процес успадковувати описувачі (handles) об'єктів батьківського процесу. Наприклад, якщо батьківський процес A уже до цього породжував процес B, те він одержав описувач процесу B і може їм маніпулювати. Якщо тепер він породжує процес C з параметром bInheritHandles рівним TRUE, то і процес C зможе працювати з описувачем процесу B;

dwCreationFlags - визначає деякі додаткові умови створення процесу і його клас пріоритету;

lpEnvironment- покажчик на блок перемінні середовища породженого процесу. Якщо цей параметр дорівнює NULL, то породжений процес успадковує середовище батька. Інакше він повинний указувати на блок рядків, що завершується нулем, кожна з який завершується нулем (аналогічно DOS);

lpCurrentDirectory - покажчик на рядок, що містить повне ім'я поточного каталогу породженого процесу. Якщо цей параметр дорівнює NULL, то породжений процес успадковує каталог батька;

lpStartupInfo - покажчик на структуру STARTUPINFO, що визначає параметри головного вікна породженого процесу;

lpProcessInformation - покажчик на структуру, що буде заповнена інформацією про породжений процес після повернення з функції.

Приклад: програма, що запускає Microsoft® Word

#include <windows.h>

#include <conio.h>

#include <stdio.h>

main()

{ PROCESS_INFORMATION pi ;

STARTUPINFO si ;

ZeroMemory( &si, sizeof(si)) ;

si.cb = sizeof( si ) ;

printf( "Press any key to start WinWord -- " );

getch() ;

CreateProcess( NULL, "WinWord", NULL, NULL, FALSE, 0,

NULL, NULL, &si, &pi ) ;

return 0 ;

}

·  Функція CreateThread()

Створює новий потік в адресному просторі процесу.

Формат функції:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибути захисту

// потоку

DWORD dwStackSize, // розмір стека в байтах

LPTHREAD_START_ROUTINE lpStartAddress, //покажчик на функцію

// потоку

LPVOID lpParameter, // аргумент, переданий у функцію

// потоку

DWORD dwCreationFlags, // прапори керування створенням потоку

LPDWORD lpThreadId // область пам'яті для повернення

// ідентифікатора потоку

);

Функція повертає описувач породженого потоку.

Параметри:

lpThreadAttributes - покажчик на структуру, що описує параметри захисту потоку. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

dwStackSize - установлює розмір стека, що приділяється потоку. Якщо параметр дорівнює нулю, то встановлюється стек, рівний стеку первинного потоку;

lpStartAddress - адреса функції, которую буде виконувати потік. Функція має один 32-бітний аргумент і повертає 32 бітне значення;

lpParameter - параметр, переданий у функцію, которую буде виконувати потік;

dwCreationFlags - додатковий прапор, що керує створенням потоку. Якщо цей параметр дорівнює CREATE_SUSPENDED, то потік після породження не запускається на виконання до виклику функціїResumeThread;

lpThreadId - покажчик на 32-бітну перемінну, котрої буде привласнене значення унікального ідентифікатора потоку.

Приклад: програма, що породжує потік

#include <stdio.h>

#include <conio.h>

#include <windows.h>

DWORD WINAPI Output( LPVOID Param )

{ while( TRUE ) {

printf( "A" ) ;

Sleep(100) ;

}

return( 0 ) ;

}

main()

{ HANDLE hThread ;

DWORD ThreadId ;

hThread = CreateThread( NULL, 0, Output, NULL, 0, &ThreadId ) ;

getch() ;

TerminateThread( hThread, 0 ) ;

return(0) ;

}