close

Вход

Забыли?

вход по аккаунту

?

оси5 (4)

код для вставкиСкачать
Работа в Delphi
1) Теоретическое введение.
1.1 Критические секции.
Критическая секция - это небольшой участок кода, требующий монопольного доступа к каким-то общим данным. Она позволяет сделать так, чтобы единовременно только один поток получал доступ к определенному ресурсу. Ни один из потоков, которым нужен занятый ресурс, не получит процессорное время до тех пор, пока поток, захвативший критическую секцию, не выйдет за ее границы.
При работе с критическими секциями выполняются следующие действия:
1. Создается экземпляр структуры CRITICAL_SECTION. Например: VAR cs:TRTLCriticalSection;
2. Инициализируется критическая секция. Сделать это надо до обращения какого-либо потока к защищенному ресурсу. Критическая секция инициализируется вызовом процедуры InitializeCriticalSection:
procedure InitializeCriticalSection(var lpCriticalSection: TRTLCriticalSection); где lpCriticalSection - адрес структуры CRITICAL_SECTION.
3. При обращении к разделяемому ресурсу, вызывается процедура EnterCriticaSecton:
procedure EnterCriticalSection(var lpCriticalSection: TRTLCriticalSection); где lpCriticalSection - адрес структуры CRITICAL_SECTION.
Процедура EnterCriticalSection допустит выполнение вызвавшего ее потока, если определит, что критическая секция свободна. В ином случае EnterCriticalSection заставит поток ждать, пока критическая секция не освободится. Процедура EnterCriticalSection занимает критическую секцию.
4. Поток, покидая участок кода, где он работал с защищенным ресурсом, должен вызвать процедуру LeaveCriticalSection. Тем самым он уведомляет систему о том, что разделяемый ресурс освободился. Прцедура LeaveCriticalSection имеет вид:
procedure LeaveCriticalSection(var lpCriticalSection: TRTLCriticalSection); где lpCriticalSection - адрес структуры CRITICAL_SECTION.
5. Если структура CRITICAL_SECTION больше не понадобится ни одному потоку, ее следует удалить, вызвав процедуру DeleteCriticalSection:
procedure DeleteCriticalSection(var lpCriticalSection: TRTLCriticalSection); где lpCriticalSection - адрес структуры CRITICAL_SECTION.
1.2 Wait - функции.
Wait-функции позволяют потоку в любой момент приостановиться и ждать освобождения какого-либо объекта ядра. Из всего семейства этих функций чаще всего используется WaitForSingleObject:
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD; где hHandle - дескриптор объект ядра, поддерживающиго состояния "свободен-занят"
dwMilliseconds - указывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта. В качестве второго параметра можно указывать константу INFINITE, которая указывает системе, что вызывающий поток готов ждать освобождения объекта "бесконечно". Возвращаемое значение функции WaitForSingleObject указывает, почему вызывающий поток снова стал планируемым Если функция возвращает WAITOBTECT_0, объект свободен, а если WAIT_TIMEOUT - заданное время ожидания (таймаут) истекло. При передаче неверного параметра (например, недопустимого дескриптора) WaitForSingleObject возвращает WAIT_ FAILED. Чтобы выяснить конкретную причину ошибки, вызывается функция GetLastError. Функция WaitForMultipleObjects аналогична WaitForSingleObject c тем исключением, что позволяет ждать освобождения сразу нескольких объектов или какого-то одного из списка объектов: function WaitForMultipleObjects(nCount: DWORD; lpHandles: PWOHandleArray; bWaitAll: BOOL; dwMilliseconds: DWORD): DWORD; Параметр nCount определяет количество объектов ядра, освобождение которых ожидается. Его значение должло быть в пределах от 1 до MAXIMUM_WAIT_OBJECTS (в заголовочных файлах Windows оно определено как 64). Параметр lpObject - это указатель на массив дескрипторов объектов ядра. WaitForMultipleObjects приостанавливает поток и засгавляет его ждать освобождения либо всех заданных объектов ядра, либо одного из них. Параметр fWaitAll определяет тип ожидания. Если он равен TRUE, функция не даст потоку возобновить свою работу, пока не освободятся все объекты. Параметр dwMilliseconds идентичен одноименному параметру функции WaitForSingleObject. Если указывается конкретное время ожидания, то по его истечении функция в любом случае возвращает управление. Возвращаемое значение функции WaitForMultipleObjects сообщает, почему возобновилосъ выполнение вызвавшего ее потока Значения WAIT_FAILED и WAIT_TIMEOUT никаких пояснений не требуют. Если в параметре fWaitAll передано TRUE в и все объекты перешли в свободное состояние, функция возвращает значение WAIT_OBJECT_0. Если fWaitAll равен FALSE, функция WaitForMultipleObjects возвращает управление, как только освобождается любой из объектов. В этом случае возвращается значение от WAIT_OBJECT_0 до WAIT_OBJECT_0 + dwCount - 1. Иначе говоря, если возвращаемое значение не равно WAIT_TIMEOUT или WAIT_FAILED, из этого значения следует вычесть WAlT_OBJECT_0, и получится индекс в массиве дескрипторов, на который указывает второй параметр функции WaitForMultipleObjects. Индекс указывает, какой объект перешел в незанятое состояние. 1.3 Объекты Mutex
Объекты ядра Mutex гарантируют потокам взаимоисключающий доступ к единственному ресурсу. Mutex ведут себя точно так же, как и критические секции. Однако, если последние являются объектами пользовательского режима, то Mutex - объекты ядра. Кроме того, объект Mutex позволяет синхронизировать доступ к ресурсу нескольких потоков из разных процессов; при этом можно задать максимальное время ожидания доступа к ресурсу. Для использования объекта Mutex один из процессов должен сначала создать его вызовом CreateMutex: function CreateMutex(lpMutexAttributes: PSecurityAttributes; bInitialOwner: BOOL; lpName: PChar): THandle; где lpMutexAttributes - указывает на структуру SECURITY_ATTRIBUTES, которая содержит информацию о защите объекта ядра "mutex". Если защиты не нужно в этот параметр заносится nil.
bInitialOwner - опрсдсляст начальное состояние мьютекса. Если в нем передается FALSE (что обычно и бывает), объект-мьютекс не принадлежит ни одному из потоков и поэтому находится в свободном состоянии. Если же в нем передается TRUE, мьютекс изначально находится в занятом состоянии.
lpName - указатель на сроку, , заканчивающуюся двоичным нулем и содержащую имя объекта "mutex". Применяется в тех случаях, когда объект "mutex" используется для синхронизации потоков разных процессов. Если мьютекс используется для синхронизации потоков одного процесса, этот параметр устанавливается в nil.
При успешном выполнении функция CreateMutex возвращает дескриптор мьютекса, В случае ошибки функция возвращает nil. Причем, если при вызове функции CreateMutex указывается имя мьютекса и объект мьютекс с таким именем уже существует, то функция вернет значение - nil, а функция GetLastError вернет значение - ERROR_ALREADY_EXISTS.
Любой процесс может получить свой ("процессо-зависимый") дескриптор существующего объекта "мьютекс", вызвав функцию OpenMutex: HANDLE OpenMutex( DWORD fdwAccess, 800L bInheritHandle, PCTSTR pszName); function OpenMutex(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: PChar): THandle; где dwDesiredAccess- определяет требуемый доступ к мьютексу. Возможные значения данного параметра приведены в таблице 7.1.
bInheritHandle- определяет тип наследования дескриптора. Если данный параметр имеет значение TRUE, процесс, создаваемый функцией CreateProcess будет наследовать данный дескриптор. Если же параметр имеет значение FALSE, дескриптор мьютекса не будет наследуемым.
lpName- указатель на сроку, заканчивающуюся двоичным нулем и содержащую имя мьютекса.
Таблица 7.1.
Значения параметра dwDesiredAccess
ЗначениеОписаниеMUTEX_ALL_ACCESSОзначает все возможные флаги доступа для мьютексаSYNCHRONIZEДопускается использование дескриптора объекта мьютекс в любой wait- функции для ожидания освобождения мьютекс. Поток получаст доступ к разделяемому ресурсу, вызывая одну из Wait-функций и передавая ей дескриптор мьютекса, который охраняет этот ресурс. Wait-функция проверяет состояние мьютекса. Если объект мьютекс свободен, Wait-функция переводит мьютекс в занятое состояние и разрешает продолжение выполнения потока.
Если Wait-функция определяет, что мьютекса занят, то поток переходит в состояние ожидания освобождения объекта мьютекс.
Когда ожидание мьютекса потоком успешно завершается, последний получает монопольный доступ к защищенному ресурсу. Все остальные потоки, пытающиеся обратиться к этому ресурсу, переходят в состояние ожидания. Когда поток, занимающий ресурс, заканчивает с ним работать, он должен освободить мьютекс вызовом функции ReleaseMutex function ReleaseMutex(hMutex: THandle): BOOL; где hMutex - дескриптор объекта мьютекс.
При успешном выполнении функция ReleaseMutex возвращает значение TRUE.
Объект мьютекс отличается от остальных объектов ядра тем, что занявшему его потоку передаются права на владение им. Объекты мьютексы способны запоминать, какому потоку они принадлежат. Если какой-то посторонний поток попытается освободить мьютекс вызовом функции ReleaseMutex, то данная функция вернет FALSE. Вызов функции GetLastError даст значение ERROR_NOT_OWNER. 1.4 Семафоры
Объекты ядра "семафор" используются для учета ресурсов Как и все объекты ядра, они содержат счетчик числа пользователей, но, кроме того, поддерживают два 32 битных значения со знаком: одно определяет максимальное число ресурсов (контролируемое семафором), другое используется как счетчик текущего числа ресурсов Для семафоров определены следующие правила: * когда счетчик текущего числа ресурсов становится больше 0, семафор переходит в свободное состояние, * если этот счетчик равен 0, семафор занят, * система не допускает присвоения отрицательных значений счетчику текущего числа ресурсов; * счетчик текущего числа ресурсов не может быть больше максимального числа ресурсов Не следует путать счетчик текущего числа ресурсов со счетчиком числа пользователей объекта-семафора Объект ядра "семафор" создается вызовом функции CreateSemapbore: function CreateSemaphore(lpSemaphoreAttributes: PSecurityAttributes; lInitialCount, lMaximumCount: Longint; lpName: PChar): THandle; где lpSemaphoreAttributes - указывает на структуру SECURITY_ATTRIBUTES, которая содержит информацию о защите объекта ядра "семафор". Если защиты не нужно в этот параметр заносится nil.
lInitialCount - счетчик текущего числа ресурсов.
lMaximumCount - максимальное число ресурсов, контролируемое семафором. Данный параметр должен быть больше 0.
lpName - указатель на сроку, , заканчивающуюся двоичным нулем и содержащую имя объекта "семафор". Применяется в тех случаях, когда объект "семафор" используется для синхронизации потоков разных процессов. Если объект "семафор" используется для синхронизации потоков одного процесса, этот параметр устанавливается в nil.
При успешном выполнении функции CreateSemaphore возвращает дескриптор семафора, В случае ошибки функция возвращает nil. Причем, если при вызове функции CreateSemaphore указывается имя семафора и объект "семафор" с таким именем уже существует, то функция вернет значение - nil, а функция GetLastError вернет значение - ERROR_ALREADY_EXISTS. 1.5 События.
События уведомляют об окончании какой-либо операции. Объекты-события бывают двух типов: со сбросом вручную (manual-reset events) и с автосбросом (auto-reset events). Первые позволяют возобновлять выполнение сразу нескольких ждущих потоков, вторые - только одного. Объекты-события обычно используют в том случае, когда какой-то поток выполняет инициализацию, а затем сигнализирует другому потоку, что тот может продолжить работу. Инициализирующий поток переводит объект "событие" в занятое состояние и приступает к своим операциям. Закончив, он сбрасывает событие в свободное состояние. Тогда другой поток, который ждал перехода события в свободное состояние, пробуждается и вновь становится планируемым. Для работы с объектом "событие" используются следующие функции:
1. Создание объекта ядра "событие", функция CreateEvent: function CreateEvent(lpEventAttributes: PSecurityAttributes; bManualReset, bInitialState: BOOL; lpName: PChar): THandle; где lpEventAttributes - указывает на структуру SECURITY_ATTRIBUTES, которая содержит информацию о защите объекта ядра "событие". Если защиты не нужно в этот параметр заносится nil.
Пареметр fManualReset (булева переменная) определяет тип объекта "событие" - событие со сбросом вручную (TRUE) или с автосбросом (FALSE). Параметру fInitialState определяет начальное состояние события - свободное (TRUE) или занятое (FALSE). lpName - указатель на сроку, , заканчивающуюся двоичным нулем и содержащую имя объекта "событие". Применяется в тех случаях, когда объект "событие" используется для синхронизации потоков разных процессов. Если объект "событие" используется для синхронизации потоков одного процесса, этот параметр устанавливается в nil. После того как система создает объект событие, CreateEvent возвращает дескриптор события, специфичный для конкретного процесса. Потоки из других процессов могут получить доступ к этому объекту: * вызовом CreateEvent с тем же параметром lpName;
* наследованием l;tcrhbgnjhf; * применением функции DuplicateHandle;
* вызовом OpenEvent c передачей в параметре lpName имени, совпадающего с указанным в аналогичном параметре функции CreateEvent. 2. Открытие объекта ядра "событие", функция OpenEvent: function OpenEvent(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: PChar): THandle; где dwDesiredAccess - определяет требуемый доступ к объекту "событие". bInheritHandle- определяет тип наследования данного дескриптора. Если данный параметр имеет значение TRUE, процесс, создаваемый функцией CreateProcess будет наследовать данный дескриптор. Если же данный параметр имеет значение FALSE, дескриптор события не будет наследуемым.
lpName - указатель на сроку, заканчивающуюся двоичным нулем и содержащую имя объекта "событие". 2) Рабочее задание.
2.1 Задание 1
С помощью объектов синхронизации Windows создать модель вычислительной сети. Сеть состоит из нескольких серверов, к которым обращаются с запросами клиенты. Запросы клиентов поступают через случайные промежутки времени. Каждый сервер имеет ограниченный размер входной очереди запросов. Запрос каждого клиента обрабатывается в течение некоторого времени. 2.2 Текст программы unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
Label2: TLabel;
Edit2: TEdit;
Label3: TLabel;
Label4: TLabel;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
hThread2: THandle;
hThread1: Array [0..1000] of THandle;
ThreadId2: DWORD;
ThreadId1: Array [0..1000] of DWORD;
serv1: THandle;
q: Integer;
zapr: Integer;
implementation
{$R *.dfm}
procedure Thread1;
var q1: Integer;
begin
q1 := q;
WaitForSingleObject(serv1,INFINITE);
if q1>0 then
begin
Sleep(1000+Random(2000));
Form1.Memo1.Lines.Add('Обработан запрос номер '+IntToStr(q1));
end;
ReleaseSemaphore(serv1,1,nil);
end;
procedure Thread2;
begin
while q<zapr do
begin
Sleep(100+Random(200));
q := q+1;
Form1.Edit3.Text := IntToStr(q);
hThread1[q] := CreateThread(nil,0,@Thread1,nil,0,ThreadId1[q]);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var res: Integer;
begin
Memo1.Clear;
q := 0;
res := StrToInt(Edit1.Text);
zapr := StrToInt(Edit2.Text);
serv1 := CreateSemaphore(nil,res,res,nil);
hThread2 := CreateThread(nil,0,@Thread2,nil,0,ThreadId2);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Application.Terminate;
end;
end.
2.2 Вид главной формы
Вывод: в результате выполнения лабораторной работы были изучены объекты синхронизации. 2
Документ
Категория
Рефераты
Просмотров
25
Размер файла
68 Кб
Теги
оси5
1/--страниц
Пожаловаться на содержимое документа