Бакнелл Джулиан М.
Шрифт:
Листинг 12.17. Методы StartConsuming и StopConsuming
procedure TtdProduceManyConsumeSync.StartConsuming(aId : integer);
var
ConsumerInfo : PConsumerInfo;
begin
{чтобы можно было начать потребление данных, потребителю с данным конкретным идентификатором должен быть передан семафор "имеются данные"}
ConsumerInfo := PConsumerInfo(FConsumerInfo[aId]);
WaitForSingleObject(ConsumerInfo^.ciHasData, INFINITE);
end;
procedure TtdProduceManyConsumeSync.StopConsuming(aId : integer);
var
BufInfo : PBufferInfo;
ConsumerInfo : PConsumerInfo;
NumToRead : integer;
begin
{мы выполнили считывание данных в буфере, на который указывает указатель начала очереди}
ConsumerInfo := PConsumerInfo(FConsumerInfo[aId]);
BufInfo := PBufferInfo(FBufferInfo[ConsumerInfo^.ciHead]);
NumToRead := InterLockedDecrement(BufInfo^.biToUseCount);
{переместить указатель начала очереди}
inc(ConsumerInfo^.ciHead);
if (ConsumerInfo^.ciHead >= FBufferCount) then
ConsumerInfo^.ciHead := 0;
{если данный поток был последним, который должен был использовать этот буфер, производителю нужно сигнализировать о необходимости генерирования новых данных}
if (NumToRead = 0) then
ReleaseSemaphore(FNeedsData, 1, nil);
end;
Конструктор и деструктор этого класса должны создавать и уничтожать большое количество объектов синхронизации, а также всю информацию о буфере и потребителе.
Листинг 12.18. Создание и уничтожение объекта синхронизации
constructor TtdProduceManyConsumeSync.Create(aBufferCount : integer;
aConsumerCount : integer);
var
NameZ : array [0..MAX_PATH] of AnsiChar;
i : integer;
BufInfo : PBufferInfo;
ConsumerInfo : PConsumerInfo;
begin
inherited Create;
{создать семафор "требуются данные"}
GetRandomObjName(NameZ, 'tdPMC.Needs Data');
FNeedsData := CreateSemaphore(nil, aBufferCount, aBufferCount, NameZ);
if (FNeedsData = INVALID_HANDLE_VALUE) then
RaiseLastWin32Error;
{создать циклическую очередь буферов и заполнить ее}
FBufferCount := aBufferCount;
FBufferInfo := TList.Create;
FBufferInfo.Count := aBufferCount;
for i := 0 to pred(aBufferCount) do
begin
New(BufInfo);
BufInfo^.biToUseCount :=0;
FBufferInfo[i] := BufInfo;
end;
{создать информационный список потребителей и заполнить его}
FConsumerCount := aConsumerCount;
FConsumerInfo := TList.Create;
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;