Главная Случайная страница


Полезное:

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


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Потоки. Функція CreateThread. Завершення потоку. Зміна класу пріоритету процесу. Установка відносного пріоритету потоку





Для создания дополнительного потока наряду с главным потоком приложения в Delphi можно использовать функцию прикладного программного интерфейса Windows (сокращенно API – Application Program Interface) для создания потока CreateThread. Для этого необходимо, во-первых, создать поток, вызвав указанную функцию, и, во-вторых, описать функцию потока, которая будет выполняться каждый раз, когда ОС будет выделять квант времени для выполнения созданного потока.
Функция CreateThread имеет следующий формат:

CreateThread(LpThreadAttributes, DwStackSize, LpStartAddress, LpParameter,
dwCreationFlags, LpThreadld);

 


Параметр LpThreadAttributes принимает серию атрибутов безопасности. Если этот параметр установлен в nil, то используются атрибуты безопасности по умолчанию.
Следующий параметр DwStackSize имеет тип DWORD и определяет размер (в байтах) стека создаваемого потока. Если этот параметр установлен в 0, то размер стека создаваемого потока будет совпадать с размером стека главного потока приложения. При определении этого параметра следует помнить, что если задается слишком большое значение, превышающее размеры доступной памяти, то система не сможет создать новый поток. Однако если заданного заранее размера стека становится недостаточно для потока, то размер стека увеличивается автоматически.
Параметр LpStartAddress указывает название функции потока, которая вызывается тогда, когда поток начинает выполняться. Здесь указывается имя функции потока, перед которым стоит символ «@».
Параметр LpParameter имеет тип Pointer и используется для передачи функции потока какого-либо инициализирующего значения.
Параметр DwCreationFlags позволяет передать определенные флаги, которые ассоциируются с потоком. Если указан флаг CREATE_SUSPENDED, то создается приостановленный поток, который не запускается на выполнение до тех пор, пока не будет вызвана функци ResumeThread. Если значение этого параметра установлено в 0, то поток запускается на выполнение сразу после создания.
Последний параметр LpThreadld имеет тип DWORD. После создания потока этому параметру будет присвоен уникальный идентификационный номер потока.
Если создание потока прошло успешно, то значением функции станет указатель на вновь созданный поток, если поток создать не удалось, то возвращаемое значение функции будет установлено в 0. После того, как создан неприостановленный поток, автоматически вызывается функция потока.
П р и м е р 1. Создается приложение, которое содержит три потока: главный и два дополнительных. Потоки будут выполнять некоторые простые вычисления, а главная программа — отображать информацию об объеме вычислений в секунду, выполненных в каждом потоке.
При выполнении потоков должна обеспечиваться возможность изменения их свойств и наблюдения за их реакцией.
Среди компонентов приложения будут использоваться два регулятора для установки приоритетов потоков, две строки редактирования — для наблюдения за их изменением, две кнопки для запуска потоков и компонент типа TTimer для подсчета времени выполнения потоков, как показано на рис.1.

Рис. 1
Новый поток будет создаваться при выполнении пользователем щелчка по соответствующей кнопке. Для этого необходимо создать обработчик события OnClick каждой кнопки. Для создания приложения следует выполнить следующие действия:
1. В разделе переменных модуля приложения опишите переменные:

var
Count1,Count2: integer; {число вычислений в секунду в потоке}
ThreadId1,ThreadId2:dword; {идентификатор создаваемого потока}
HThread1, HThread2: THandle; {указатель на создаваемый поток}

 


2. Для создания потока воспользуемся функцией CreateThread. Значения параметров зададим следующим образом. Атрибуты безопасности установим по умолчанию. Определим размер стека создаваемого потока — такой же, что и для главного потока приложения. Пусть функция первого потока будет называться Execute1, а второго – Execute2. В качестве атрибутов создания определим неприостановленный поток, а в качестве идентификатора потока укажем переменную ThreadID. В результате вызов функции создания первого потока будет иметь следующий вид:

HThread1:=CreateThread (nil, 0, @ Execute1, nil, 0, ThreadID1);

 


Второй поток создается аналогичным образом. Оформленные в таком виде вызовы функции CreateThread должны быть реализованы как обработчики кнопок «Поток 1» и «Поток 2».
3. Как уже было сказано, не все потоки, выполняющиеся в системе, одинаковы. Некоторые потоки получают от ОС больше времени для выполнения, некоторые — меньше. Доля времени выполнения потока задается операционной системой в зависимости от установленного для данного потока приоритета. Чем выше приоритет потока, тем больше времени для его выполнения выделяется ОС.
В Delphi для установления приоритета потока используется функция

SetThreadPriority(hThread, nPriority);

 


Параметр hThread определяет указатель на поток, для которого определяется приоритет, nPriority — задает приоритет потока.
Если установление приоритета потока прошло успешно, то значение функции SetThreadPriority устанавливается в True, иначе — в False.
Информацию об основных типах приоритетов потоков можно получить, используя справочную систему Delphi.
В создаваемом приложении установка и изменение приоритета каждого потока будет выполняться с помощью регулятора компонента TrackBar.
Выполните щелчок на левом регуляторе TrackBar1 и выберите страницу Events в окне Object Inspector. Затем выполните двойной щелчок напротив имени метода OnChange для создания шаблона метода, который будет вызываться каждый раз при изменении положения регулятора. Метод будет устанавливать регулятор в соответствии с задаваемым приоритетом потока. Для первого потока код метода будет следующим:

SetThreadPriority(HThread1,TrackBar1.Position);

 


Аналогично выглядит обработчик события OnChange для второго поток а.
4. Чтобы ограничить приоритет потоков значением не больше максимального, предельное правое положение регуляторов компонента TrackBar должно быть ограничено четырьмя. Для этого нужно выбрать TrackBar1, и затем, удерживая клавишу, выбрать TrackBar2. Когда оба компонента будут выделены, выбрать в окне Object Inspector страницу Properties и установить для свойства Max значение
5. Компонент TTimer в данном примере будет использоваться для того, чтобы приложение могло отслеживать состояние потоков. Выполнив двойной щелчок на компоненте TTimer для создания шаблона метода Timer, введите текст следующей процедуры:

procedure TForm1.Timer1Timer (Sender: TObject);
begin
form1.Edit1.Text:=intTostr(Count1);
Count1:=0;
form1.Edit2.Text:=intToStr(Count2);
Count2:=0;
end;

 


Этот метод будет автоматически вызываться каждую секунду, чтобы приложение могло отслеживать состояние потоков.
6. Действия, выполняемые в процедурах Execute1 и Execute2, заключаются в том, чтобы подсчитать среднее значение десяти случайных чисел и затем увеличить на единицу значение соответственно Count1 и Count2. Текст процедуры для первого потока имеет вид:

procedure Execute1;
var
I, Total, Avg: integer;
begin
while True do
Begin
Total:=0;
For i:=1 To 10 Do inc(Total, Random(Maxint));
Avg:=Avg Div 10; inc(Count1);
End;
end;

 


Аналогично реализуется процедура Execute2. Тексты обеих процедур должны быть размещены в разделе реализации модуля приложения.
7. Запустите подготовленное приложение на выполнение. Изменяя приоритеты, проанализируйте их влияние на производительность одновременно выполняющихся потоков. Обратите внимание на скорость реакции ОС при изменении приоритетов потоков.

Тема: «Создание потоков в Win32 API для ОС MS Windows». Создается поток функцией CreateThread, которая имеет следующий прототип: HANDLE CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты защиты DWORD dwStackSize, // размер стека потока в байтах LPTHREAD_START_ROUTINE lpStartAddress,// адрес исполняемой функции LPVOID lpParameter,// адрес параметра DWORD dwCreationFlags,// флаги создания потока LPDWORD lpThreadId// идентификатор потока); При успешном завершении функция CreateThread возвращает дескриптор созданного потока и его идентификатор, который является уникальным для всей системы. В противном случае эта функция возвращает значение NULL. Кратко опишем назначение параметров функции CreateThread. Параметр lpThreadAttributes устанавливает атрибуты защиты создаваемого потока. До тех пор пока мы не изучим структуру системы безопасности в Windows, то есть раздел Windows NT Access Control из интерфейса программирования приложений Win32 API, мы будем устанавливать значения этого параметра в NULL при вызове почти всех функций ядра Windows. Это означает, что атрибуты защиты потока совпадают с атрибутами защиты создавшего его процесса. О процессах будет подробно рассказано в следующем разделе. Параметр dwStackSize определяет размер стека, который выделяется потоку при запуске. Если этот параметр равен нулю, то потоку выделяется стек, размер которого равен по умолчанию 1 Мб. Это наименьший размер стека, который может быть выделен потоку. Если величина параметра dwStackSize меньше, значения, заданного по умолчанию, то все равно потоку выделяется стек размеров в 1Мб. Операционная система Windows округляет размер стека до одной страницы памяти, который обычно равен 4 Кб. Параметр lpStartAddress указывает на исполняемую потоком функцию. Эта функция должна иметь следующий прототип: DWORD WINAPI ThreadProc (LPVOID lpParameters); Параметр lpParameter является единственным параметром, который будет передан функции потока. Параметр dwCreationFlags определяет, в каком состоянии будет создан поток. Если значение этого параметра равно 0, то функция потока начинает выполняться сразу после создания потока. Если же значение этого параметра2 равно CREATE_SUSPENDED, то поток создается в подвешенном состоянии. В дальнейшем этот поток можно запустить вызовом функции ResumeThread. Параметр lpThreadId является выходным, то есть его значение устанавливает Windows. Этот параметр должен указывать на переменную, в которую Windows поместит идентификатор потока, который уникален для всей системы и может в дальнейшем использоваться для ссылок на поток. Приведем пример программы, которая использует функцию CreateThread для создания потока, и продемонстрируем способ передачи параметров исполняемой потоком функции. // Пример создания потока функцией CreateThread #include #include volatile int n; DWORD WINAPI Add(LPVOID iNum) { cout << "Thread is started." << endl; n += (int)iNum; cout << "Thread is finished." << endl; return 0; } int main() { int inc = 10; HANDLE hThread; DWORD IDThread; cout << "n = " << n << endl; hThread = CreateThread(NULL, 0, Add, (void*)inc, 0, &IDThread); if (hThread == NULL) return GetLastError(); // ждем пока поток Add закончит работу WaitForSingleObject(hThread, INFINITE); // закрываем дескриптор потока Add CloseHandle(hThread); cout << "n = " << n << endl; return 0; } Отметим, что в этой программе используется функция WaitForSingleObject, которая ждет завершения потока Add.

16. Архітектура пам'яті в Win32. Віртуальний адресний простір.

рхитектура системы управления памятью в Win32 и Win64

Win32 (в данном случае различия между Win32 и Win64 становятся существенными) — это API 32-разрядных ОС семейства Windows. "32-разрядность" проявляет себя при адресации памяти тем, что указатели (LPSTR, LPDWORD и так далее) являются 4-байтовыми (32-битовыми) объектами. Win64 API предоставляет виртуальное адресное пространство гораздо большего объема, и 64-битовые указатели являются естественным результатом эволюции Win32. Тем не менее, о переносимости приложений на платформу Win64 необходимо заботиться отдельно. Настоящее обсуждение будет относиться только к Win32; вопросы миграции приложений на платформу Win64 обсуждаются в главе 16, где также приводятся ссылки на соответствующие источники информации.

Далее, в рамках Win32 у каждого процесса имеется собственное виртуальное адресное пространство объемом 4 Гбайт (2 32 байт). Разумеется, объем виртуального адресного пространства в Win64 гораздо больше. По крайней мере, половину указанного пространства (2-3 Гбайт; расширение до 3 Гбайт должно производиться во время загрузки) Win32 делает доступной для процесса. Оставшаяся часть виртуального адресного пространства выделяется для совместно используемых данных и кода, системного кода, драйверов и так далее.

Хотя детали описанного распределения памяти и заслуживают интереса, здесь они обсуждаться не будут; прикладные программы используют абстрактные модели памяти, предоставляемые API. С точки зрения программиста ОС просто предоставляет адресное пространство большого объема для размещения кода, данных и других ресурсов. В этой главе мы сосредоточим свое внимание на использовании средств управления памятью в Windows, не заботясь о том, как все это реализуется в ОС. Тем не менее, ниже приводится соответствующий краткий обзор.

рхітектура пам'яті, використовувана операційною системою, - ключ до розуміння того, що в ній відбувається. Не маючи уявлення про неї, неможливо відповісти на такі питання:

§ Як підвищити ефективність додатка?

§ Як створити дані, що розділяються двома застосуваннями?

§ Де зберігаються системні змінні оточення?

Як відомо, об'єм пам'яті, що адресується, визначається розміром регістра команд, який зазвичай залежить від довжини машинного слова. У часи, коли ця довжина дорівнювала 16 бітам, можна було без особливих хитрувань звернутися до будь-якого байта з діапазону (0, 216-1), або 65536 = 64 Кбайт. Звернення до адрес пам'яті поза цим діапазоном коштувало певних зусиль.

Потім, як ви пам'ятаєте, довжина регістра команд стала рівною 20 бітам і з'явилася можливість адресувати пам'ять в діапазоні (0, 220-1) або 1 048 576 = 1 Мбайт. Правда через те, що довжина машинного слова залишалася рівною 16 бітам, доводилося мати справу з сегментами пам'яті по 64 Кбайт, базою, зсувом, зрушеннями і так далі

Тепер, коли нарешті довжина машинного слова і регістра команд стали рівними 32 бітам, ми можемо вільно адресувати будь-який байт з діапазону (0, 232-1), або 4 294 967 296 = 4 Гбайт. Оскільки реально ми не маємо такого об'єму пам'яті, то нам пропонують навчитися жити на віртуальному світі, а точніше, адресному просторі Windows. На цьому світі, як ви знаєте кожен процес отримує свій адресний простір об'ємом 4 Гбайт. Корпорація Microsoft забезпечує цю, що реально не існує, пам'ять за допомогою механізму підкочування сторінок пам'яті (page swapping), який дозволяє використовувати частину жорсткого диска для імітації оперативної пам'яті. Звичайно, процесор здатний працювати лише із справжньою пам'яттю типа RAM, якій рівно стільки, скільки ви купили і встановили, але ви можете розробляти додатки, не замислюючись про це обмеження, і вважати, що кожен процес володіє простором в 4 Гбайт. Як тільки в програмі відбувається звернення до адреси пам'яті, яка вище реально доступного, операційна система завантажує (підкачує) ті, що не дістають дані з жорсткого диска в RAM і працює з ними звичайним способом.

У MS-DOS і 16-бітовою Windows всі процеси розташовуються в єдиному адресному просторі, і тому будь-який процес може прочитувати і записувати будь-яку ділянку пам'яті, у тому числі і що належить іншому процесу або операційній системі. На такому світі стан процесу і його благополуччя залежать від поведінки інших процесів. У Win32 пам'ять, відведена іншим процесам, прихована від поточного потоку і недоступна йому. У Windows NT/2000 пам'ять самої ОС прихована від будь-якого виконуваного потоку. У Windows 95 остання властивість не реалізована, тому в ній поточний потік може зіпсувати пам'ять, належну ОС.

Отже, адресний простір процесу - це його приватна власність, яка неприкосновенна/Поэтому первинні потоки всіх процесів, що одночасно існують у фізичній пам'яті, завантажуються з однієї і тієї ж адреси. У Windows NT/2000 - це 0x00400000 (4 Мбайт). Таке можливе лише на віртуальному світі, в якому реальні адреси фізичної пам'яті не збігаються з віртуальними адресами в просторі процесу. Як система відображує віртуальні адреси в реальні? Виявляється, що Windows 95 робить це не так, як Windows NT/2000. Ми розглядатимемо лише останній випадок, оскільки перший хоч і відрізняється від нього, але ці відмінності можуть зацікавити лише обмежений контингент розробників, орієнтованих на розробку додатків лише для Windows 95.

 

 

Date: 2015-07-27; view: 946; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.005 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию