Чтение онлайн

на главную - закладки

Жанры

Фундаментальные алгоритмы и структуры данных в Delphi

Бакнелл Джулиан М.

Шрифт:

var

HaveToWait : boolean;

begin

{перехватить управление критическим разделом}

EnterCriticalSection(FController);

{при наличии еще одного запущенного потока записи или активных потоков считывания, метод добавляет себя в качестве ожидающего потока считывания и обеспечивает переход в состояние ожидания}

if FActiveWriter or (FActiveReaders <> 0) then begin

inc(FWaitingWriters);

HaveToWait := true;

end

{в противном случае метод должен добавить себя в качестве еще одного выполняющегося потока записи и обеспечить отсутствие состояния ожидания}

else begin

FActiveWriter :=true;

HaveToWait := false;

end;

{освободить

управление критическим разделом}

LeaveCriticalSection(FController);

{при необходимости ожидания нужно выполнить следующее}

if HaveToWait then

WaitForSingleObject(FBlockedWriters, INFINITE);

end;

При отсутствии каких-либо других выполняющихся потоков можно сразу начать запись. Метод увеличивает значение счетчика выполняющихся потоков записи, освобождает управление критическим разделом и осуществляет выход из подпрограммы. В любом случае, сразу по выходу из подпрограммы значение счетчика активных потоков записи оказывается установленным равным единице (либо самим этим методом, либо методом StopReading - если помните, это происходит Непосредственно перед передачей семафора заблокированных потоков записи).

И, наконец, можно приступить к рассмотрению метода StopWriting, код которого приведен в листинге 12.5.

Как и ранее, первоначальная задача состоит в перехвате управления критическим разделом. Затем, поскольку запись завершена, метод уменьшает значение счетчика активных потоков записи. Теперь выполняется проверка количества ожидающих потоков считывания. Мы входим в цикл, который уменьшает значение счетчика активных потоков считывания и освобождает семафор. Семафор, в свою очередь, освобождает от ожидания один поток считывания. Со временем, по завершении цикла, все потоки считывания будут освобождены и смогут считаться активными (обратите внимание, что они все будут использовать соответствующее обращение к методу StartReading). Если, с другой стороны, не существует никаких ожидающих потоков считывания, метод выполняет проверку на наличие каких-либо ожидающих потоков записи. Если такие потоки существуют, метод освобождает только один поток записи таким же образом, как уже было описано при рассмотрении метода StopReading. И, наконец, независимо ни от чего, метод освобождает управление критическим разделом.

Листинг 12.5. Метод StopWriting

procedure TtdReadWriteSync.StopWriting;

var

i : integer;

begin

{перехватить управление критическим разделом}

EnterCriticalSection(FController);

{запись завершена}

FActiveWriter := false;

{если имеется хотя бы один ожидающий поток записи, освободить их всех}

if (FWaitingReaders <> 0) then begin

FActiveReaders := FWaitingReaders;

FWaitingReaders := 0;

ReleaseSemaphore(FBlockedReaders, FActiveReadersr nil);

end

{в противном случае, при наличии по меньшей мере одного ожидающего потока записи, ему необходимо предоставить свободу действий}

else

if (FWaitingWriters <> 0) then begin

dec(FWaitingWriters);

FActiveWriter :=true;

ReleaseSemaphore(FBlockedWriters, 1, nil);

end;

{освободить управление критическим разделом}

LeaveCriticalSection(FController);

end;

Нам осталось рассмотреть только два метода: конструктор Create и деструктор Destroy.

Код реализации этих методов показан в листинге 12.6.

Листинг 12.6. Создание и уничтожение объекта синхронизации

constructor TtdReadWriteSync.Create;

var

NameZ : array [0..MAXJPATH] of AnsiChar;

begin

inherited Create;

{создать примитивные объекты синхронизации}

GetRandomObjName (NameZ, ' tdRW.BlockedReaders' );

FBlockedReaders := CreateSemaphore(nil, 0, MaxReaders, NameZ);

GetRandomObjName(NameZ, 'tdRW.BlockedWriters');

FBlockedWriters := CreateSemaphore(nil, 0, 1, NameZ);

InitializeCriticalSection(FController);

end;

destructor TtdReadWriteSyhc.Destroy;

begin

CloseHandle(FBlockedReaders);

CloseHandle(FBlockedWriters);

DeleteCriticalSection(FController);

inherited Destroy;

end;

Как видите, конструктор Create будет создавать три примитивных объекта синхронизации, а деструктор Destroy будет, соответственно, их уничтожать.

Полный исходный код класса TtdReadWriteSync можно найти на Web-сайте издательства, в разделе материалов. После выгрузки материалов отыщите среди них файл TDRWSync.pas.

Алгоритм производителей-потребителей

Еще один многопоточный алгоритм, тесно связанный с проблемой потоков считывания и записи - алгоритм, решающий проблему производителей и потребителей.

Этот раздел адресован только тем программистам, которые работают в среде 32-раздядной Windows. Delphi I вообще не поддерживает многопоточную обработку, в то время как Kylix и Linux не предоставляют необходимых примитивных объектов синхронизации, с помощью которых можно было бы решить проблему производителей-потребителей.

В этой ситуации имеется один или более потоков, создающих данные (их называют производителями (producers)), которые будут использоваться или потребляться одним или большим количеством других потоков (называемых потребителями (consumers)). Как видите, эта задача тесно связана с алгоритмом потоков считывания-записи: потребителей можно считать потоками считывания данных, записанных производителями. Примером использования этого алгоритма может послужить программа потокового видео: в этом случае будет существовать поток, который загружает видео из какого-то Web-сайта, и поток, который воспроизводит загруженное видео. Ни один из этих потоков не должен беспокоиться о том, что должен делать второй.

Мы сымитируем этот процесс подпрограммой копирования нескольких потоков. Производитель будет копировать данные из потока в очередь буферов. Затем потребитель будет копировать данные из буферов в другой поток. Например, мог бы существовать производитель, считывающий несжатые данные из потока, и два потребителя данных: один, сжимающий данные в другой поток с помощью одного алгоритма, и второй, сжимающий их с помощью другого алгоритма, что теоретически позволяет выбирать более плотно упакованные данные. В этом случае производитель может продолжать работу и пытаться максимально быстро заполнять буфера в очереди, а потребители, в свою очередь, могут пытаться максимально быстро их считывать. Работа производителя будет тормозиться, если потребители работают недостаточно быстро и очередь заполняется непрочитанными буферами. Аналогично, работа потребителей будет замедляться, если производитель работает медленно и очередь опустошается.

Поделиться:
Популярные книги

Лорд Системы 12

Токсик Саша
12. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 12

Младший научный сотрудник 2

Тамбовский Сергей
2. МНС
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Младший научный сотрудник 2

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Цеховик. Книга 2. Движение к цели

Ромов Дмитрий
2. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цеховик. Книга 2. Движение к цели

Неестественный отбор.Трилогия

Грант Эдгар
Неестественный отбор
Детективы:
триллеры
6.40
рейтинг книги
Неестественный отбор.Трилогия

Попаданка в семье драконов

Свадьбина Любовь
Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.37
рейтинг книги
Попаданка в семье драконов

Звезда сомнительного счастья

Шах Ольга
Фантастика:
фэнтези
6.00
рейтинг книги
Звезда сомнительного счастья

Беглец

Кораблев Родион
15. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Беглец

Я – Орк

Лисицин Евгений
1. Я — Орк
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я – Орк

Смерть может танцевать 2

Вальтер Макс
2. Безликий
Фантастика:
героическая фантастика
альтернативная история
6.14
рейтинг книги
Смерть может танцевать 2

Идеальный мир для Лекаря 18

Сапфир Олег
18. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 18

Жандарм

Семин Никита
1. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
4.11
рейтинг книги
Жандарм

Путь Шедара

Кораблев Родион
4. Другая сторона
Фантастика:
боевая фантастика
6.83
рейтинг книги
Путь Шедара

Гром над Империей. Часть 1

Машуков Тимур
5. Гром над миром
Фантастика:
фэнтези
5.20
рейтинг книги
Гром над Империей. Часть 1