【发布时间】:2012-01-30 20:13:38
【问题描述】:
我刚刚发现了 OmniThreadLibrary 并开始使用它。我正在尝试启动最多不超过 20 个任务并将其余任务发送到队列中。
我修改了 OmniThreadLibrary 的 00_Beep 项目来做到这一点:
const
TASKS_COUNT = 100;
procedure TfrmTestSimple.btnBeepClick(Sender: TObject);
var
I: Integer;
begin
with OmniEventMonitor do
for I := 1 to TASKS_COUNT do
Monitor(CreateTask(Beep, 'Beep-' + IntToStr(I))).Schedule;
end;
procedure TfrmTestSimple.FormCreate(Sender: TObject);
begin
GlobalOmniThreadPool.MonitorWith(OmniEventMonitor);
GlobalOmniThreadPool.MaxExecuting := 20;
GlobalOmniThreadPool.MaxQueued := 0;
end;
它有效,但如果我将任务数(即 TASKS_COUNT)增加到 7000,我会得到一个异常:
TOmniCommunicationEndpoint.Send: Queue is full
我阅读了我能找到的所有内容(OTL 博客和论坛、示例项目、google 了很多等等),似乎为了防止这种情况,我必须定期清空队列。
所以我尝试了这个,但没有成功:
procedure TfrmTestSimple.OmniEventMonitorTaskTerminated(const task: IOmniTaskControl);
begin
Task.Terminate(1); // I also tried: Task.Terminate(0);
Task.Comm.Reader.Empty; // Task.Comm.OtherEndpoint.Reader.Empty; didn't work either
Task.Comm.Writer.Empty; // Task.Comm.OtherEndpoint.Writer.Empty; didn't work either
end;
关于如何清空队列并避免此异常的任何建议?
我知道有些人可能会说队列中的任务如此之多是荒谬的,我只想说这既不是假设性问题,也不在我的问题范围内,告诉我重新设计我的应用程序,此时我只需要知道OTL中排队系统的限制以及如何绕过这个限制。
提前致谢!
【问题讨论】:
-
缩写“AV”表示访问冲突。这真的是你得到的吗?看起来你只是遇到了一个普通的逻辑错误——队列已满,你正试图在其中放入更多的东西。要清空它,您是要阻塞您的程序直到排队的项目被执行,还是要放弃排队的项目并继续排队新项目?
-
@Rob:我跟踪了消息来源,OTL 出现了异常。理想情况下,我希望队列能够动态扩展(我刚刚开始像 24 小时一样玩 OTL,我仍然不完全了解 OTL)
-
简单看一下代码,发现了一个 const 'CDefaultQueueSize = 1000;'在 OtlComm 单元中。 'OtlThreadPool: 'owtCommChannel := CreateTwoWayChannel(100, owtTerminateEvent);' 中还有一个有趣的调用我找不到任何设置为 7000 的内容。您应该查看这些限制 - 一个或多个可能是相关的。您的池中有多少线程 - 我认为每个池线程可能有一个单独的输入队列(大小 100?)。
-
@Rob:我很抱歉,我应该更明确一点。我最初认为,每当一个任务完成时,OTL 就会从队列中读取下一个任务的信息,启动新任务,然后将其从队列中删除。至少那是我认为 OTL 的队列正在做的事情。所以回答你的问题:这两个选项都不适合我,理想情况下我希望队列动态扩展/收缩(即,一旦任务启动,它就会从队列中删除并移动到池中)。不过好像不太可能……?
-
请注意,OTL 队列是环形缓冲区,可能是为了避免在推送/弹出时分配/解除分配。环形缓冲区的大小在初始化期间设置。
标签: multithreading delphi omnithreadlibrary