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

FConsumerInfo.Count := aConsumerCount;

for i := 0 to pred(aConsumerCount) do

begin

New(ConsumerInfo);

FConsumerInfo[i] := ConsumerInfo;

GetRandomObjName(NameZ, 'tdPMC.HasData');

ConsumerInfo^.ciHasData :=

CreateSemaphore(nil, 0, aBufferCount, NameZ);

if (Consumer Info^.ciHasData = INVALID__HANDLE__VALUE) then

RaiseLastWin32Error;

ConsumerInfo^.ciHead := 0;

end;

end;

destructor TtdProduceManyConsumeSync.Destroy;

var

i : integer;

BufInfo : PBufferInfo;

ConsumerInfo : PConsumerInfo;

begin

{уничтожить семафор "требуются данные"}

if (FNeedsData <> INVALID_HANDLE_VALUE) then

CloseHandle(FNeedsData);

{уничтожить информационный список потребителей}

if (FConsumerInfo <> nil) then begin

for i := 0 to pred(FConsumerCount) do

begin

ConsumerInfo := PConsumerInfo(FConsumerInfo[i]);

if (ConsumerInfo <> nil) then begin

if (ConsumerInfo^.ciHasData <> INVALID__HANDLE__VALUE) then

CloseHandle(ConsumerInfo^.ciHasData);

Dispose(ConsumerInfo);

end;

end;

FConsumerInfo.Free;

end;

{уничтожить информационный список буферов}

if (FBufferInfo <> nil) then begin

for i := 0 to pred(FBufferCount) do

begin

BufInfo := PBufferInfo(FBufferInfo[i]);

if (BufInfo <> nil) then

Dispose(BufInfo);

end;

FBufferInfo.Free;

end;

inherited Destroy;

end;

Хотя, на первый взгляд, кажется, что в программе листинга 12.18 выполняется множество действий, в действительности все достаточно просто. Конструктор Create должен создать список буферов и заполнить его требуемым числом записей о буферах. Он должен также создать список потребителей и заполнить его соответствующим количеством записей о потребителях. Для каждой записи потребителя должен быть создан отдельный семафор. Деструктор Destroy должен уничтожить все эти объекты и освободить всю выделенную память.

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

В качестве примера программы мы рассмотрим подпрограмму многопоточного копирования, выполняющую копирование потока в три других потока. Как и в случае примера, приведенного в листинге 12.14, производитель будет считывать исходный поток в буфера, количество которых может доходить до 20. Потребители, количество которых теперь равняется трем, будут считывать буфера и выполнять запись в собственные потоки.

Класс TQueuedBuffers (листинг 12.19) должен быть несколько изменен, поскольку ему необходимо хранить указатель начала очереди для нескольких потребителей и, следовательно, он должен содержать массив таких указателей.

Листинг 12.19. Класс TQueuedBuffers для модели с несколькими потребителями type

PBuffer = ^TBuffer;

TBuffer = packed record

bCount : longint;

bBlock : array [0..pred(BufferSize) ] of byte;

end;

PBufferArray = ^TBufferArray;

TBufferArray = array [0..pred(MaxBuffers) ] of PBuffer;

TQueuedBuffers = class private

FBufCount : integer;

FBuffers : PBufferArray;

FConsumerCount : integer;

FHead : array [0..pred(MaxConsumers)] of integer;

FTail : integer;

protected

function qbGetHead(aInx : integer): PBuffer;

function qbGetTail : PBuffer;

public

constructor Create(aBufferCount : integer;

aConsumerCount : integer);

destructor Destroy; override;

procedureAdvanceHead(aConsumerId : integer);

procedure AdvanceTail;

property Head [aInx : integer] : PBuffer read qbGetHead;

property Tail : PBuffer read qbGetTail;

property ConsumerCount : integer read FConsumerCount;

end;

constructor TQueuedBuffers.Create(aBufferCount : integer;

aConsumerCount : integer);

var

i : integer;

begin

inherited Create;

{распределить буферы}

FBuffers := AllocMem(aBufferCount * sizeof(pointer));

for i := 0 to pred(aBufferCount) do

GetMem(FBuffers^[i], sizeof(TBuffer));

FBufCount := aBufferCount;

FConsumerCount := aConsumerCount;

end;

destructor TQueuedBuffers.Destroy;

var

i : integer;

begin

{освободить буферы}

if (FBuffers <> nil) then begin

for i := 0 to pred(FBufCount) do

if (FBuffers^[i] <> nil) then

FreeMem(FBuffers^[i], sizeof(TBuffer));

FreeMem(FBuffers, FBufCount * sizeof(pointer));

end;

inherited Destroy;

end;

procedure TQueuedBuffers.AdvanceHead(aConsumerId : integer);

begin

inc(FHead[aConsumerId]);

if (FHead[aConsumerId] = FBufCount) then

FHead[aConsumerId] := 0;

end;

procedure TQueuedBuffers.AdvanceTail;

begin

inc(FTail);

if (FTail = FBufCount) then

FTail := 0;

end;

function TQueuedBuffers.qbGetHead(aInx : integer): PBuffer;

begin

Result := FBuffers^[FHead[aInx]];

end;

function TQueuedBuffers.qbGetTail : PBuffer;

begin

Result := FBuffers^ [FTail];

end;

Следующей мы рассмотрим реализацию классов производителя и потребителя (листинг 12.20). Класс производителя претерпел не слишком много изменений по сравнению с предыдущей реализацией, в то время как класс потребителя теперь содержит идентификационный номер, посредством которого он обращается к объекту буферов для получения нужного указателя начала очереди.

Листинг 12.20. Классы производителя и потребителя

type

TProducer * class(TThread) private

FBuffers : TQueuedBuffers;

FStream : TStream;

FSyncObj : TtdProduceManyConsumeSync;

protected

procedure Execute; override;

public

constructor Create(aStream : TStream;

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных