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

2023-12-28

尝试在单生产者多消费者方案中使用 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.

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

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

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


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TThreadedQueue 不能支持多个消费者吗? 的相关文章

  • 如何更改 Chromium 组件的默认背景颜色?

    I use TChromium http code google com p delphichromiumembedded 我分配AWebPageAsString这是一个带有灰色背景颜色的静态 HTML 页面 FBrowser TChrom
  • 如何更新Delphi对象检查器?

    继我最近发布的这个问题之后 组件编辑器可以在多个组件上执行吗 https stackoverflow com questions 14802371 can a component editor be executed on multiple
  • 如何添加资源并使用它们

    在我的应用程序中 我想添加 2 个图像作为资源 我想使用这些图像 当我在应用程序中单击 是 按钮时 第一张图像将被设置为壁纸 当我在应用程序中单击 否 按钮时 第二张图像将被设置为桌面壁纸 提前致谢 regards 最简单的方法是创建一个文
  • Delphi (Indy) TIdTCPClient 在线程中

    在互联网上 我看到通常将 TIdTCPClient 放置在自定义 TThread 后代中 为什么要这样做 有时我也在这样的线程中看到服务器 为什么 干杯 阿德里安 Indy 使用阻塞 I O 最好在线程中处理 这是 Indy 整体设计的核心
  • 如何将我的图标添加到组件选项板页面中的组件? [复制]

    这个问题在这里已经有答案了 可能的重复 Delphi非可视化组件图像 https stackoverflow com questions 3319276 delphi non visual component image 如何将我的图标添加
  • VCL.位图到 FMX.位图

    我在网上找到了这段代码 但 FMX Bitmap 没有扫描线 是否可以以某种方式将 VCL TBitmap 复制或绘制到 FMX Bitmap IFDEF MSWINDOWS type TBitmap FMX Types TBitmap T
  • 如何确保 FormClose 程序运行,无论程序如何退出?

    在 Delphi 7 中 我有一个 TMainForm FormClose 过程 旨在在程序退出时写出一些状态 这在手动关闭程序时效果很好 但是 我发现如果程序被 Windows 强制 退出 例如在 Windows 更新后需要重新启动 则不
  • 加载 Jpg/Gif/Bitmap 并转换为 Bitmap

    我必须从 XML 文件加载图像 XML 文件中没有关于图像是否为 JPG GIF BMP 的信息 加载图像后 我需要将其转换为位图 有谁知道如何在不知道实际文件格式的情况下将图像转换为位图 我正在使用 Delphi 2007 2009 谢谢
  • Delphi线程死锁

    我有时会在销毁某些线程时遇到死锁问题 我尝试过调试该问题 但在 IDE 中调试时似乎从未存在死锁 可能是因为 IDE 中的事件速度较低 问题 当应用程序启动时 主线程会创建多个线程 线程始终处于活动状态并与主线程同步 完全没有问题 当应用程
  • delphi 变量值在循环中的线程中发生变化

    我的代码正在运行一个 for 循环来处理一些数据 如下所示 procedure printValue Value Integer begin TThread Synchronize TThread Current procedure beg
  • 在运行时按需更改组件类

    我的问题与这里的想法类似 替换delphi中的组件类 https stackoverflow com q 4685863 937125 但我需要改变一个specific按需组件类 这是一些伪演示代码 unit Unit1 TForm1 cl
  • Firemonkey 编辑/组合自动完成/打字时自动建议

    实施方式是什么Autocomplete or Autosuggest适用于 Windows Android 平台以及 MacOS 和 iOS 的 Delphi Firemonkey Example 当用户在 Google 搜索框中输入文本时
  • 如何在 Delphi REST 中发布内容类型为“multipart/form-data”的数据?

    我正在尝试使用 REST API 发送请求multipart form data作为内容类型 我总是收到 HTTP 1 1 500 Internal Error 作为响应 我尝试向需要的方法发送请求application x www for
  • 运行delphi客户端自动化程序后excel.exe保持加载状态的原因是什么?

    我编写了一个 Delphi 程序 该程序从单个 XLS 文件的多个不同电子表格中提取数据并将其合并到文本文件中以供以后处理 这是德尔福7console程序 最相关的代码片段的摘录将向您表明 显然 我的程序表现得相当好 或者至少达到了它需要的
  • std::queue 初始化为 NULL

    是否可以初始化一个C std queue with a NULL像其他变量一样的值 像这样 HANDLE variable NULL class Test i e std queue
  • Delphi 返回 TList 时出错

    我做了一个非常简单的应用程序 但我有一个我真的无法理解的问题 看一下这个基本代码 unit Unit1 interface uses Winapi Windows Winapi Messages System SysUtils System
  • 处理 TShellListView 后代中的文件放置

    我正在尝试创建 TShellListView 的后代 它接受从 Windows 资源管理器中删除的文件 我想在组件定义中处理拖 放操作 而不必在任何使用该组件的应用程序中实现它 我找到了接受从 Windows 资源管理器中拖放的文件的示例
  • 线程安全的异步字节队列

    我有一个回调方法 只要有新数据可用 就会调用该方法 public delegate void DataCallback byte buffer int offset int count 我想将其包装在一个实现与此类似的接口的类中 publi
  • 使用 Matplotlib、PyQt 和 Threading 进行实时绘图导致 python 崩溃

    我一直在努力研究我的 Python 应用程序 但找不到任何答案 我有 PyQT GUI 应用程序 它使用 Matplotlib 小部件 GUI 启动一个新线程来处理 mpl 小部件的绘图 恐怕我现在通过从另一个线程访问 matplotlib
  • Word 2010 自动化:“转到书签”

    我有一个用 Delphi 7 编写的程序 它打开一个基于模板的新 Word 文档 文档打开后 系统会自动跳转到书签 在模板中预定义 并在其中添加一些文本 以下代码在 Word 2003 中工作正常 但会导致invalid variant o

随机推荐

  • WPF中上标的上标

    我已经设法使用以下代码行创建字符上标 Paragraph p new Paragraph Span s new Span s BaselineAlignment BaselineAlignment Superscript s Inlines
  • 使用 XML 序列化时是否有办法避免自闭合标签?

    我正在使用 VB NET 但遇到 XML 序列化问题 当我正在序列化的对象中存在空值时 XML 文件包含以下标签
  • Python3 写入文件 beautifulsoup

    我希望用以下代码编写 beautifulsoup 表单 soup BeautifulSoup con content f open Desktop littletext rtf w f write str soup f close 我收到此
  • 从 Web 视图中的链接打开 Mobile Safari

    是否有 URI 方案可将 Mobile Safari 打开到特定 URL e g a href Open Google in Safari a Update 因此 从 iOS 6 0 2 开始 仍然没有特定于 MobileSafari 的
  • 尝试附加附件通过 request.post 发送时,表单数据库抛出无法读取 null 属性的错误

    当我尝试制作一个request post with form data对于附件 我收到以下错误 该错误来自表单数据库 var filename options filename value name value path TypeError
  • 直接使用 ld 链接 C 程序失败,未定义对“__libc_csu_fini”的引用

    我正在尝试在Linux下编译C程序 然而 出于好奇 我尝试手动执行一些步骤 我使用 gcc 前端生成汇编代码 然后运行GNU汇编器来获取目标文件 然后将其与 C 运行时链接以获得可工作的可执行文件 现在我被链接部分困住了 该程序是一个非常基
  • 如何使用 python 获取文件的扩展 MacOS 属性?

    我有兴趣使用 python 从文件中获取更多信息 我知道使用 os stat 如下所示 会返回有关文件的信息 但我想从文件中获取其他属性 例如 来自哪里 os stat filename posix stat result st mode
  • 如何从 C 代码中获取单操作数 imul

    我必须用 C 语言编写什么才能让汇编器显示imul与一个操作数 例如 imul ebp 如果你想编写 C 代码以便编译器发出imul对于一个操作数 唯一的方法是使用扩大有符号乘法 即将操作数转换为有符号类型寄存器长度的两倍 因此 在 32
  • 单选按钮被选中的事件?

    是否有一些单选按钮被选择的事件 我知道我可以使用 单击 但我相信可以在某些浏览器中设置单选按钮的样式 这样单击单选按钮的外部区域可能不会选择该单选按钮 我应该使用什么事件 这取决于您想何时获知该事件 如果您想立即了解 请前往click IE
  • java中向上转换的内存分配

    考虑这些类 public class Animal public class Dog extends Animal public AnimalTest public static void main String args Dog d ne
  • 将 Stripe 与 Devise 结合使用以实现 Ruby on Rails 订阅

    我正在尝试将 Stripe 的定期支付系统与 Devise 集成 使用 Ryan 最近的 Railscast 作为指南 http railscasts com episodes 288 billing with stripe view as
  • Blend“WPF 项目不支持窗口”

    我对 Blend 报告 Windows Presentation Foundation WPF 项目不支持窗口 感到沮丧 由于无法构建的配置 但无法完全弄清楚如何摆脱它 我发现这可能是由于我尝试使用 x86 和 x64 配置的单一解决方案
  • 二进制可执行文件是可移植的

    编译 C 程序后 我可以获取二进制可执行文件 并在另一个没有加载 gcc 的系统 例如 Ubuntu 系统 上运行它吗 技术上 是的 但如果您需要最大的可移植性 请使用静态链接 严格来说你不需要gcc 但你可能需要各种库 默认情况下 语言处
  • CSS 将所选文本的一部分向右对齐[重复]

    这个问题在这里已经有答案了 这是我的 HTML 的样子
  • 如何使两个按钮并排且响应灵敏?

    我有一个小任务 在使用桌面时需要并排两个按钮 然后在移动设备上它们堆叠在一起但尺寸没有减小 我已经设法将它们堆叠在一起 但它们的大小不同 每当我定义按钮的 大小时 它们都会挤在一起 在设备视图中看起来很丑陋 button backgroun
  • 动画系统的神经网络大小

    我决定使用神经网络来为我拥有的动画引擎创建行为 神经网络为我身体的每个部位接收 3 个向量和 1 个欧拉角 第一个向量 3 是位置 第二个向量是速度 第三个向量是角速度 欧拉角是身体部位的旋转角度 我的身体有 7 个部位 这些数据类型中的每
  • SQL:仅比较日期与月份和年份列

    我有一张桌子MonthlyShipments看起来像 partnumber quantity month year part1 12 6 2011 part1 22 5 2011 part1 32 4 2011 part1 42 3 201
  • Linux fedora tc qdisc 出现“错误:未找到指定的 qdisc”。

    我正在尝试在 Linux fedora 上运行以下命令 sudo tc qdisc add dev enp2s0 handle 1 0 root netem delay 0 loss 1 我检查了接口 enp2s0 并且设置正常 但我收到以
  • 创建 Vec 时借用的值存在的时间不够长

    编者注 这个问题是在 Rust 1 0 之前提出的 从那时起 许多函数和类型都发生了变化 某些语言语义也发生了变化 问题中的代码不再有效 但答案中表达的想法可能有效 我正在尝试列出目录中的文件并将文件名复制到我自己的目录中Vec 我尝试了几
  • TThreadedQueue 不能支持多个消费者吗?

    尝试在单生产者多消费者方案中使用 TThreadedQueue Generics Collections 德尔福 XE 这个想法是将对象推入队列并让多个工作线程排空队列 但它并没有按预期工作 当两个或多个工作线程调用 PopItem 时 将