gpt4 book ai didi

delphi - TThreadedQueue 不能支持多个消费者吗?

转载 作者:行者123 更新时间:2023-12-03 14:32:43 24 4
gpt4 key购买 nike

尝试在单生产者多消费者方案中使用 TThreadedQueue (Generics.Collections)。 (德尔福-XE)。这个想法是将对象插入队列并让多个工作线程耗尽队列。

但是它并没有按预期工作。当两个或多个工作线程调用 PopItem 时,将从 TThreadedQueue 中抛出访问冲突。

如果对 PopItem 的调用是通过关键部分序列化的,则一切都很好。

当然,TThreadedQueue 应该能够处理多个消费者,那么我是否遗漏了一些东西,或者这是 TThreadedQueue 中的一个纯粹的错误?

这是一个产生错误的简单示例。

program TestThreadedQueue;

{$APPTYPE CONSOLE}

uses
// FastMM4 in '..\..\..\FastMM4\FastMM4.pas',
Windows,
Messages,
Classes,
SysUtils,
SyncObjs,
Generics.Collections;

type TThreadTaskMsg =
class(TObject)
private
threadID : integer;
threadMsg : string;
public
Constructor Create( ID : integer; const msg : string);
end;

type TThreadReader =
class(TThread)
private
fPopQueue : TThreadedQueue<TObject>;
fSync : TCriticalSection;
fMsg : TThreadTaskMsg;
fException : Exception;
procedure DoSync;
procedure DoHandleException;
public
Constructor Create( popQueue : TThreadedQueue<TObject>;
sync : TCriticalSection);
procedure Execute; override;
end;

Constructor TThreadReader.Create( popQueue : TThreadedQueue<TObject>;
sync : TCriticalSection);
begin
fPopQueue:= popQueue;
fMsg:= nil;
fSync:= sync;
Self.FreeOnTerminate:= FALSE;
fException:= nil;

Inherited Create( FALSE);
end;

procedure TThreadReader.DoSync ;
begin
WriteLn(fMsg.threadMsg + ' ' + IntToStr(fMsg.threadId));
end;

procedure TThreadReader.DoHandleException;
begin
WriteLn('Exception ->' + fException.Message);
end;

procedure TThreadReader.Execute;
var signal : TWaitResult;
begin
NameThreadForDebugging('QueuePop worker');
while not Terminated do
begin
try
{- Calling PopItem can return empty without waittime !? Let other threads in by sleeping. }
Sleep(20);
{- Serializing calls to PopItem works }
if Assigned(fSync) then fSync.Enter;
try
signal:= fPopQueue.PopItem( TObject(fMsg));
finally
if Assigned(fSync) then fSync.Release;
end;
if (signal = wrSignaled) then
begin
try
if Assigned(fMsg) then
begin
fMsg.threadMsg:= '<Thread id :' +IntToStr( Self.threadId) + '>';
fMsg.Free; // We are just dumping the message in this test
//Synchronize( Self.DoSync);
//PostMessage( fParentForm.Handle,WM_TestQueue_Message,Cardinal(fMsg),0);
end;
except
on E:Exception do begin
end;
end;
end;
except
FException:= Exception(ExceptObject);
try
if not (FException is EAbort) then
begin
{Synchronize(} DoHandleException; //);
end;
finally
FException:= nil;
end;
end;
end;
end;

Constructor TThreadTaskMsg.Create( ID : Integer; Const msg : string);
begin
Inherited Create;

threadID:= ID;
threadMsg:= msg;
end;

var
fSync : TCriticalSection;
fThreadQueue : TThreadedQueue<TObject>;
fReaderArr : array[1..4] of TThreadReader;
i : integer;

begin
try
IsMultiThread:= TRUE;

fSync:= TCriticalSection.Create;
fThreadQueue:= TThreadedQueue<TObject>.Create(1024,1,100);
try
{- Calling without fSync throws exceptions when two or more threads calls PopItem
at the same time }
WriteLn('Creating worker threads ...');
for i:= 1 to 4 do fReaderArr[i]:= TThreadReader.Create( fThreadQueue,Nil);
{- Calling with fSync works ! }
//for i:= 1 to 4 do fReaderArr[i]:= TThreadReader.Create( fThreadQueue,fSync);
WriteLn('Init done. Pushing items ...');

for i:= 1 to 100 do fThreadQueue.PushItem( TThreadTaskMsg.Create( i,''));

ReadLn;

finally
for i:= 1 to 4 do fReaderArr[i].Free;
fThreadQueue.Free;
fSync.Free;
end;

except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.

更新:TMonitor中导致TThreadedQueue崩溃的错误在Delphi XE2中已修复。

更新2:上述测试强调队列处于空状态。 Darian Miller 发现,在满状态下对队列施加压力,仍然可以在 XE2 中重现该错误。错误再次出现在TMonitor 中。请参阅下面他的回答以获取更多信息。还有 QC101114 的链接。

更新3:在 Delphi-XE2 update 4 中,发布了对 TMonitor 的修复,可以解决 TThreadedQueue 中的问题。到目前为止,我的测试无法再重现 TThreadedQueue 中的任何错误。当队列为空和满时测试单个生产者/多个消费者线程。还测试了多个生产者/多个消费者。我将读取器线程和写入器线程从 1 更改为 100,没有出现任何故障。但了解历史后,我敢于让其他人破坏TMonitor

最佳答案

好吧,如果没有大量测试就很难确定,但看起来这确实是一个错误,无论是在 TThreadedQueue 还是在 TMonitor 中。不管怎样,它都在 RTL 中,而不是在您的代码中。您应该将其作为质量控制报告归档,并使用上面的示例作为“如何重现”代码。

关于delphi - TThreadedQueue 不能支持多个消费者吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4856306/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com