Установка приоритета потока
.docУстановка приоритета потока
Не все потоки должны создаваться равноправными. Существует возможность установки уровня приоритетности потока, чтобы поток получал больше или меньше ресурсов процессора по сравнению с другими потоками. Функция, которая служит для установки приоритета потока, называется SetThreadPriority().
Действительное количество циклов процессора, которые получает поток, зависит и от его приоритета, и от класса приоритета процесса, к которому этот поток принадлежит. Для определения класса приоритета процесса можно пользоваться функцией GetPriorityClass(), а установки класса приоритета — SetPriorityClass(). Все функции, о которых упоминается в этом разделе, являются функциями Windows API.
Программа, представленная в листингах 5.14 и 5.15, является С++ВшЫег-верси-ей программы, написанной на Delphi Дэвидом Интерсаймоном (David Intersimone), сотрудником Borland. Эту программу можно найти в каталоге ThSorts в коде, предназначенном для этой главы. Данная программа использует две пустые формы, названные Sec Form и ThForm. (У этой программы есть историческое прошлое: она была написана в самолете, пассажиры которого летели на презентацию Windows 95 в Сиэтле, а после этого была усовершенствована в самолете по пути на недавнюю конференцию Borland в Германии.)
Листинг S.14. Заголовок программы Дэвида Интерсаймона Dreaded Sorts, версия
для C++Builder
//
#ifndef MainH #define MainH
//_ — — __ — __„______.„__.___ „ _._
#include <Classes.hpp>
#include <Controls.hpp>
♦include <StdCtrls.hpp>
ttinclude <Forms.hpp>
#include <ComCtrls.hpp>
//
const int pixeloffset = 5; // смещение пикселей отвечает за рамку внутри окна
// количество пикселей между главной формой и окнами сортировки const int formgap =10;
const TColor formcolor = clBlack; // цвет фона окон сортировки const TColor pixelcolor = clwhite; // цвет сортируемых элементов данных //
class TForml : public TFonn
{
published: // IDE-managed Components
TButton *Buttonl;
TEdit *Editl;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TTrackBar *BubbleTrackBar;
TTrackBar *QuickTrackBar;
TLabel *Label4;
TLabel *Label5;
void fastcall ButtonlClick(TObject «Sender);
void fastcall FormDestroy(TObject *Sender);
void fastcall FormCreate(TObject *Sender);
private: // User declarations
HANDLE Tl;
HANDLE T2;
int ScreenWidth, ScreenHeight, SortWindowClientArea;
int FrameSize, CaptionSizem, SortWindowSize; public: // User declarations
int* a;
int* b;
int Numltems;
fastcall TForml(TComponent* Owner);
};
//
extern PACKAGE TForml *Forml;
// _
#endif
Листинг 5.15. Главный модуль программы Дэвида Интерсаймона Dreaded Sorts,
версия C++Builder
//
#include <vcl.h>
#pragma hdrstop
//
#include "Main.h"
#include "SecForm.h"
#include "ThForm.h"
//
#pragma package(smart_init) #pragma resource "*.dfm" TForml *Forml;
/ / „ щ m _„_ ш
fastcall TForml::TForml(TComponent* Owner)
: TForm(Owner), a(0), b(0) {
)
//
// Процедура пузырьковой сортировки — вызывается функцией BubbleThread void BubbleSortfint* ia, int items) {
HDC DC = GetDC(Form2->Handle); int t;
for (int i = items;i>0;i--) {
for (int j = 0;j<items;j++) if (iatj] < ia[j+l]) {
t = ia[j];
// Чтобы взять значение из массива, используйте индекс SetPixel(DC, ia[j+l]+pixeloffset, j+1+pixeloffset, formcolor); SetPixeKDC, iatj] +pixeloffset, j+pixeloffeet, formcolor); ia[j] = ia[j+l]; ia[j + l] = t;
SetPixeKDC, ia[ j+1]+pixelof fset, j+1+pixelof fset, pixelcolor) ; SetPixeKDC, ia[j]+pixeloff set, j+pixelof fset, pixelcolor); } ) ReleaseDC(Form2->Handle, DC);
}
// --
// Быстрая сортировка - вызывается функцией QuickThread
void Quicksort(int* ia, int iLo, int iHi)
{
int T;
int Lo = iLo;
int Hi = iHi;
int mid = ia[(Lo+Hi) / 2];
HDC DC; .■•■..
do { .,'■,.' ■ '■■ • ! ■ ,■ :
DC = GetDC(Form3->Handle); while (ia[Lo] < mid)
Lo++; while (ia[Hi] > mid)
Hi — ;
if (Lo <= Hi) {
T = ia[Lo];
SetPixelfDC, ia[Lo)+pixelof£set,Lo+pixeloffset, formcolor); SetPixel(DC, ia[Hi]+pixeloffset,Hi+pixeloffset, formcolor); ia[Lo] = ia[Hi]; ia[Hi] = T;
SetPixel(DC, ia[Lo]+pixeloffset,Lo+pixeloffset, pixelcolor); SetPixel(DC, ia[Hi]+pixeloffset,Hi+pixeloffaet, pixelcolor); Lo++; Hi--;
// sleep(5); }
} while (Lo <= Hi);
if (Hi > iLo) Quicksort(ia,iLo,Hi); if (Lo < iHi) Quicksort (ia,Lo, iHi); ReleaseDC(Form3->Handle, DC);
}
/ /_ , ч —— „_ _.„ _«._
// Функция потока для пузырьковой сортировки
DWORD CALLBACK BubbleThread(void* parms)
{
BubbleSort(Porml->a,Porml->NumItems-l);
return 0; } //
// Функция потока для быстрой сортировки DWORD CALLBACK QuickThread(void* parms) {
Quicksort(Forml->b,0,Forml->NumItems-l);
return 0;
} - -
//
void fastcall TForml::ButtonlClick(TObject «Sender)
{
DWORD ThreadID;
// Размещение формы пузырьковой сортировки на рабочем столе
delete Form2;
Form2 = new TForm2(this);
Form2->Top = Forml->Top+Forml->Height+formgap;
Form2->Left = (ScreenWidth-(SortWindowSize*2)) / 2;
// Размещение окна пузырьковой сортировки на левой половине экрана
Form2->Width = SortWindowSize;
Porm2->Keight = SortWindowSize;
Form2->Color = formcolor;
Form2->Caption = "Bubble Sort";
Form2->Show();
// Размещение формы быстрой сортировки на рабочем стопе
delete Form3;
Form3 • new TForm3(this);
Form3->Top = Forml->Top+Forml->Height+formgap;
Form3->Left = Form2->Left+Form2->Width; // Размещение окна быстрой
// сортировки на правой половине экрана
Form3->Width = SortWindowSize;
Form3->Height = SortWindowSize;
Form3->Color = formcolor;
Form3->Caption = "Quick Sort";
Form3->Show() ;
// Набор элементов для сортировки, равный
// ширина клиентской области — смещение границ
Numltems = Form2->ClientHeight — pixeloffset*2;
// Распределение массива для хранения сортируемых данных
delete[] a;
а ■ new int[Numlterns];
delete [] b;
b = new int[Numltems];
// Генерация случайных чисел для сортировки
randomize();
for (int i = O;i<NumItems;i++)
{
a[i] ■ random(Numltems);
b[i] = a[i];
Form2->Canvas->Pixels[a[i]+pixeloffset][i+pixeloffeet] « pixelcolor;
Form3->Canvas->Pixels[b[i]+pixeloffset][i+pixeloffeet] a pixelcolor;
}
// Запуск потока пузырьковой сортировки
Tl ■ CreateThread(O,O,BubbleThread,O,O,&ThreadID);
// Установка приоритета потока в соответствии с позицией track bar
SetThreadPrioritytTl, BubbleTrackBar->Poeition);
// Запуск потока быстрой сортировки
Т2 = CreateThread(0,O,QuickThread,0,O,&ThreadID);
// Установка приоритета потока в соответствии с позицией track bar
SetThreadPriority(Т2, QuickTrackBar->Posit ion);
// ПРИМЕЧАНИЕ: Для того чтобы осуществить быструю рекурсивную // сортировку, установите приоритет ее потока в -1 II -2.
// Чтобы увидеть, сможет ли пузырьковая сортировка осуществляться быстрее // чем быстрая, установите приоритет потока пузырьковой сортировки в +2, // а быстрой в -2
)
// .
void fastcall TForml::FormDestroy(TObject *Sender)
<
delete [] a;
delete[] b;
)
/уиии¥ _ — -_ — __..__ — ___ — _
void fastcall TForml::FormCreate(TObject *Sender)
{
// Получаем размер рабочего стола
ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// Перемещаем главную форму вверх и в центр рабочего стола
Forml->Top = 0;
Forml->Left = (ScreenWidth - Forml->Width) / 2;
// Определяем, сколько элементов может быть показано в этих двух окнах
SortWindowSize = ScreenHeight-Forml->Height;
if (SortWindowSize > (ScreenWidth / 2))
SortWindowSize = ScreenWidth / 2; }
Программа Treaded Sorts создает два потока. Один поток выполняет пузырьковую сортировку, а второй — быструю сортировку. Вы можете использовать компоненты trackbar для повышения приоритета пузырьковой сортировки, чтобы она получила больше циклов процессора, при одновременном понижении приоритета быстрой сортировки. В конечном итоге можно достичь состояния, когда пузырьковая сортировка будет выполняться примерно за один и тот же интервал времени что и быстрая, несмотря на то, что пузырьковая сортировка — это более медленный алгоритм. Две дополнительных формы в проекте служат для визуального отображения процесса сортировок (рис. 5.5).
Рис. 5.5. Программа Threaded Sorts и вспомогательные окна, иллюстрирующие разные методы сортировки.
В коде устанавливается приоритет потоков:
Т1 = CreateThread(O,O,BubbleThread,O,O,&ThreadID); SetThreadPriority(Tl, BubbleTrackBar~>Position); Т2 = CreateThread(O,O,QuickThread,nil,O,&ThreadID); SetThreadPriority(T2, QuickTrackBar->Position);
Каждому потоку с помощью функции SetThreadPriorityO назначается его приоритет. Ниже приводится объявление функции SetThreadPriorityO:
BOOL SetThreadPriority(
HANDLE hThread, // дескриптор потока
int nPriority // уровень приоритетности потока
);
Во второй параметр функции SetThreadPriorityO могут быть переданы следующие константы:
THREAD_PRIORITY_ LOWEST = THREAD_BASE_PRIORITY_MIN; THREAD_PRIORITY__BELOW_NORMAL = THREAD__PRIORITY_LOWEST + 1; THREAD_PRIORITY_NORMAL = 0 ;
THREAD__PRIORITY_HIGHEST = THREAD_.BASE_PRIORITY_MAX; THREAD_PRIORITY._ABOVE_NORMAL = THREAD_PRIORITY_HIGHEST - 1; THREAD_PRIORITY_TIME_CRITICAL = THREAD_BASE_PRIORITY_L0WRT; THREAD_PRIORITY._IDLE = THREAD_BASE__PRIORITY_IDLE;
Для того чтобы придать смысл значениям, указанным выше, можно использовать следующий код:
// приоритет устанавливается в значение LowRealtime — 1 THREAD_BASE_PRIORITY_LOWRT = 15;
// максимальное увеличение базовой приоритетности потока THREAD_BASE_PRIORITY__MAX = 2;
// максимальное уменьшение базовой приоритетности потока THREAD_BASE_PRIORITY_MIN ■ -2; THREAD__BASE_PRIORITY_IDLE = -15; // значение, останавливающее поток
ПРИМЕЧАНИЕ НАУЧНОГО РЕДАКТОРА
Вышеперечисленные четыре константы именно таким образом определены в заголовочном файле WINNT.H
Связанные с этой темой функции Windows API, описание которых можно найти в интерактивной справке Win32, — SetPriorityClass() и GetPriorityClass().
Программа Treaded Sorts интересна для изучения. Если вас увлекла эта тема, вам следует потратить на нее какое-то время. Можно и просто откинуться на спинку кресла и получить удовольствие, наблюдая за ее работой.
Повторный обзор потоков в C++Builder
Вы уже убедились в том, что даже довольно сложные манипуляции с потоками могут осуществляться достаточно просто. Используя информацию о мощной технологии потоков, полученную из этой книги, вы сможете многое сделать в своих программах. Однако будьте внимательны и не злоупотребляйте потоками. Если вы слишком увлечетесь, то, возможно, столкнетесь с проблемами, связанными с усложненной структурой программы. Используйте вторичные потоки только тогда, когда они действительно необходимы и когда вы ясно понимаете, как они вписываются в вашу программу. Избегайте создавать программы, которые окажутся запутанным клубком потоков. Результатом этого будет сумбурность кода и сложность его сопровождения.
В многопроцессорных системах различные потоки могут выполняться на различных процессорах, что является чрезвычайно мощной концепцией. Только представьте себе, что один Pentium выполняет графический код, второй анализирует электронную таблицу, а третий в это же время открывает SQL-запрос. В многозадачном мире программирования в C++Builder возможно запустить даже потоки одновременно на