为什么 WaitForMultipleObjects 在使用多个线程句柄时会失败?

2023-11-21

在下面的测试程序中,每个测试线程将其句柄添加到全局TThreadList当它开始执行时,并在执行即将结束时从同一列表中删除其句柄。

此外,出于测试目的,每个线程确保在主线程锁定列表之前添加其句柄(以复制其句柄并开始等待它们完成)。这些线程还确保在主线程锁定列表之前它们不会删除其句柄。

测试程序在最多 50-60 个线程下运行良好。之后,WaitForMultipleObjects调用开始失败WAIT_FAILED, GetLastError返回 87 (ERROR_INVALID_PARAMETER)。目前它启动了 100 个线程。我的问题是,我做错了什么?

该程序是使用 XE2 - update 4、32 位目标平台编译的。测试盒为W7x64。

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  windows,
  sysutils,
  classes,
  syncobjs;

type
  TTestThread = class(TThread)
  private
    FAckStarted: TEvent;
    function GetAckHandle: THandle;
    class var
      ThreadList: TThreadList;
      WaitEnd: THandle;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    property AckHandle: THandle read GetAckHandle;
  end;

{.$DEFINE FREEONTERMINATE}

constructor TTestThread.Create;
begin
  inherited Create(True);
  FAckStarted := TEvent.Create;
{$IFDEF FREEONTERMINATE}
  FreeOnTerminate := True;
{$ENDIF}
end;

destructor TTestThread.Destroy;
begin
  FAckStarted.Free;
  inherited;
end;

procedure TTestThread.Execute;
begin
//  OutputDebugString(PChar(Format('%d starting -------------', [Handle])));
  ThreadList.Add(Pointer(Handle));
  FAckStarted.SetEvent;

  NameThreadForDebugging(AnsiString(IntToStr(Handle)));

  WaitForSingleObject(WaitEnd, INFINITE);
  ThreadList.Remove(Pointer(Handle));
//  OutputDebugString(PChar(Format('%d leaving -------------', [Handle])));
end;

function TTestThread.GetAckHandle: THandle;
begin
  Result := FAckStarted.Handle;
end;

const
  NumThreads = 100;

var
  DeferThreadEnd: TEvent;
  ThreadList: array of TThread;
  i: Integer;
  Thread: TTestThread;
  WaitThreadStart: THandle;
  LockList: TList;
  LockListCount: Integer;
  ThreadHandleArr: array of THandle;
  WaitRet: DWORD;
begin
  IsMultiThread := True;
  ReportMemoryLeaksOnShutdown := True;

  TTestThread.ThreadList := TThreadList.Create;
  DeferThreadEnd := TEvent.Create;
  TTestThread.WaitEnd := DeferThreadEnd.Handle;

  SetLength(ThreadList, NumThreads);
  for i := 0 to NumThreads - 1 do begin
    Thread := TTestThread.Create;
    ThreadList[i] := Thread;
    WaitThreadStart := Thread.GetAckHandle;
    Thread.Start;
    WaitForSingleObject(WaitThreadStart, INFINITE);
  end;

  LockList := TTestThread.ThreadList.LockList;
  LockListCount := LockList.Count;
  SetLength(ThreadHandleArr, LockListCount);
  for i := 0 to LockListCount - 1 do
{$IFDEF FREEONTERMINATE}
    Win32Check(DuplicateHandle(GetCurrentProcess, THandle(LockList[i]),
            GetCurrentProcess, @ThreadHandleArr[i], SYNCHRONIZE, True, 0));
{$ELSE}
    ThreadHandleArr[i] := THandle(LockList[i]);
{$ENDIF}
  TTestThread.ThreadList.UnlockList;

  DeferThreadEnd.SetEvent;
  if LockListCount > 0 then begin
    Writeln('waiting for ', LockListCount, ' threads');
    WaitRet := WaitForMultipleObjects(LockListCount,
                              PWOHandleArray(ThreadHandleArr), True, INFINITE);
    case WaitRet of
      WAIT_OBJECT_0: Writeln('wait success');
      WAIT_FAILED: Writeln('wait fail:', SysErrorMessage(GetLastError));
    end;
  end;

  for i := 0 to Length(ThreadList) - 1 do begin
{$IFDEF FREEONTERMINATE}
    Win32Check(CloseHandle(ThreadHandleArr[i]));
{$ELSE}
    ThreadList[i].Free;
{$ENDIF}
  end;
  DeferThreadEnd.Free;
  TTestThread.ThreadList.Free;
  Writeln('program end');
  Readln;
end.

The WaitForMultipleObjects() 文档 states:

对象句柄的最大数量为 MAXIMUM_WAIT_OBJECTS。

的价值MAXIMUM_WAIT_OBJECTS是 64(定义在winnt.h),因此 100 个句柄超出了限制。但是,该文档还解释了如何克服该限制:

要等待超过 MAXIMUM_WAIT_OBJECTS 个句柄,请使用以下方法之一:

  • 创建一个线程来等待 MAXIMUM_WAIT_OBJECTS 句柄,然后等待该线程和其他句柄。使用此技术将句柄分成 MAXIMUM_WAIT_OBJECTS 组。

  • 调用 RegisterWaitForSingleObject 以等待每个句柄。线程池中的等待线程等待 MAXIMUM_WAIT_OBJECTS 个注册对象,并在对象收到信号或超时间隔到期后分配工作线程。

查看答案这个问题作为第一种技术的示例。

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

为什么 WaitForMultipleObjects 在使用多个线程句柄时会失败? 的相关文章

  • Delphi AES 库 (Rijndael) 使用 KAT Vectors 进行测试

    对于这两个库 Delphi 加密概要 v 5 2 http code google com p delphidec TurboPower 密码箱 v 2 07 http lockbox seanbdurkin id au tiki list
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 如何在运行时(Delphi/Windows)程序中添加代码?

    我正在Windows XP Delphi 7上工作 我需要在正在运行的程序中添加一些过程 或函数 并且我不想在完成后再次重新编译它 我只有一个具有 5 个功能的主机应用程序来发送不同类型的警报 但是还有其他新的警报类型 所以我必须执行新的功
  • 向无锁队列添加阻塞函数

    我有一个基于循环缓冲区的无锁多生产者 单消费者队列 到目前为止 它只有非阻塞push back and pop front 来电 现在我想添加这些调用的阻塞版本 但我想尽量减少这对使用非阻塞版本的代码性能的影响 也就是说 它不应该将它们变成
  • 如何复制文件并具有取消复制的功能?

    我正在努力拥有program能够取消复制 因此我不能使用Microsoft VisualBasic FileIO FileSystem CopyFile 有一些包装用于CopyFileEx在网络上 例如here http msdn micr
  • FileSystemWatcher 在队列中丢失文件

    我写了一个FileSystemWatcher为每个文件调用一次 pgm 但我的一些文件丢失了 我只用 10 11 个文件测试了代码 文件的删除会被正确记录 但创建不会被正确记录 某些文件未记录 我的 TASK 实施可能存在问题吗 或者有什么
  • 如何使用单独的线程部分重绘自定义 SurfaceView 而不会丢失以前的编辑?

    我目前在按照自定义绘图时遇到问题SurfaceView来自不在我的主 UI 上的线程 这SurfaceView占据整个屏幕 Galaxy S3 全屏 并且必须从多个来源进行更新 问题是习惯SurfaceView不会保存 UI 更新之间的更改
  • 无法访问类型的封闭实例。 [复制]

    这个问题在这里已经有答案了 整个代码是 public class ThreadLocalTest ThreadLocal
  • Java-线程与CPU的关系

    我对多线程还很陌生 我正在开发一个项目 尝试在我的 Java 程序中使用 4 个 CPU 我想做类似的事情 int numProcessors Runtime getRuntime availableProcessors ExecutorS
  • JavaFX Platform.runLater 的使用以及从不同线程访问 UI

    我有几个问题Platform runLater 我有一个 JavaFX 应用程序类 在这个类中 我运行一个线程 该线程从网络套接字读取数据 现在当我创建一个新的Stage在线程内部 系统抛出异常 JavaFX 事件调度程序线程和我的网络读取
  • 如何在其他核心上运行每个线程?

    我有一个 udp 服务器接收数据并计算它 每个角色我都有两个线程 我的CPU是8个多核 我以不同的速度发送数据 但最多我只使用了 cpu 两核 50 的 14 如果我发送更多的数据值 我的缓冲区将填满并且不会使用更多的CPU 为什么每个核心
  • 命名管道性能问题

    我使用命名管道进行 C 和 Delphi 之间的过程间通信 C 使用System IO Pipes包 而 Delphi 使用Libby s pipes pas 不幸的是 通信几乎是高性能的 分析显示通信占用了整个运行时间的 72 其余的用于
  • 可升级读锁的优点?

    我想知道使用可升级读锁与执行这些步骤相比有什么优势 获取读锁 检查条件以查看是否需要进行写锁定 释放读锁 采取写锁定 执行更新 释放写锁 与获取可升级读锁相比 执行上述步骤的一个明显缺点是 步骤 3 和步骤 4 之间存在一个时间窗口 其中另
  • 查找字符串是否在列表中的最佳方法(没有泛型)

    我想做这样的事情 Result MyString in string1 string2 string3 string4 这不能与字符串一起使用 我不想做这样的事情 Result MyString string1 or MyString st
  • 如何处理来自单独线程的窗口消息?

    我希望启动一个单独的线程来处理窗口消息 通过阻塞 GetMessage 循环 但之后仍然在初始线程中创建窗口 在单独的线程中 一旦启动 我就会调用PeekMessage使用 PM NOREMOVE 确保消息队列存在 有必要吗 然后 Atta
  • 每个托管线程是否都有自己对应的本机线程?

    我想知道是否在 Net 中创建托管线程 通过调用Thread Start 导致在后台创建一个本机线程 那么托管线程是否有对应的本机线程呢 如果是 当托管线程等待或睡眠时 是否意味着相应的本机线程也在等待或睡眠 是的 NET 线程映射到所有当
  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 在比较 Delphi 表单文件的版本时,如何使 Beyond Compare 忽略某些差异

    我使用Beyond Compare 版本3 1 10 来比较不同版本的Delphi Form Files 但我不想看到有关ExplicitTop ExplicitLeft ExplicitHeight 和ExplicitWidth 的差异
  • delphi THashSHA2 在大文件上返回错误的 SHA256

    Data Cloud CloudAPI pas has class function TCloudSHA256Authentication GetStreamToHashSHA256Hex const Content TStream str
  • TThread.resume 在 Delphi-2010 中已弃用,应该在什么地方使用?

    在我的多线程应用程序中 I use TThread 挂起 and TThread resume 自从将我的应用程序移至 Delphi 2010 后 我收到以下警告消息 DCC 警告 xxx pas 277 W1000 符号 Resume 已

随机推荐

  • BigInteger 还是不是 BigInteger?

    在Java中 大多数基本类型都是带符号的 用一位来表示 因此当我超出类型的限制时 我可能会得到意想不到的结果 比如负数 有没有比使用 BigInteger 更好的解决方案 因为 BigInteger 存在性能问题 并且您需要使用类方法进行基
  • Robolectric 中的 getSystemService 返回具有 null Context 的对象

    在我的活动中onCreate I have AudioManager audioManager AudioManager getSystemService Context AUDIO SERVICE 当使用 Robolectric 测试活动
  • scipy 最小化 SLSQP - 'LSQ 子问题中的奇异矩阵 C'

    我正在尝试使用 SciPy 解决一个非常基本的优化问题 这个问题是受约束的并且具有可变范围 我很确定它是线性的 当我运行以下代码时 执行失败并显示错误消息 LSQ 子问题中的奇异矩阵 C 有谁知道可能是什么问题 提前致谢 编辑 我将在此处添
  • 如何获得动词的过去式? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 获取动词过去式的最有效方法
  • 如何设置 .NET WindowsAuthentication - 当我希望它使用实际用户时,名称始终显示为“IIS APPPOOL\Classic .NET AppPool”

    我使用以下代码通过 Kerberos 进行身份验证 IntPtr logonToken WindowsIdentity GetCurrent Token string authenticationType WindowsAuthentica
  • C# 将 GMT 日期字符串解析为 DateTime

    我在用着http www eyecon ro bootstrap datepicker 插件选择日期 选择日期后我得到例如Fri Nov 01 2013 00 00 00 GMT 0100 1 如果我使用 format 设置插件 为什么我会
  • 覆盖 AngularJS URL 验证器

    AngularJS 接受这个作为有效的 URL var URL REGEXP ftp http https w 0 1 w S 0 9 w Django 接受这一点 regex re compile r http ftp s http or
  • Objective-C 中的字符串常量是如何存储/检索的?

    有人可以解释编译器在何处以及如何存储字符串常量以及运行时如何访问它们吗 首先是强制性的 你不应该关心编译器如何做到这一点 任何基于编译器如何执行此操作的行为都是对无法保证的事物的危险依赖 并且可能会根据编译器的优化方式而改变 不要基于此编写
  • jQuery 未按正确顺序执行?

    我最近开始使用 jQuery 今天注意到它对我的行为有一个奇怪的问题 据我了解 JavaScript 是单线程的 因此它的所有操作都应该以 FIFO 为基础运行 然而 对我来说情况似乎并非如此 请考虑以下事项 设置如下 HTML 3 div
  • IntelliJ 中关于 Groovy 类的“类已存在”错误

    在 IntelliJ 2016 2 及之前版本 中 我们将 Groovy 类标记为红色 并显示错误 类已存在 我认为我们可以排除存根生成的原因 因为它已被停用 可能是我们的星座引起的 我们已将编译的 groovy 和 java 类包含在注册
  • 为什么 Spring AOP 不在运行时编织外部 jar?

    我有一个基于 Spring 3 构建的 java 应用程序 该项目有另一个 jar 作为依赖项 该依赖项包含一个 org aspectj lang annotation Aspect类 可以说 com aspectprovider aspe
  • SonarQube 无法启动 MariaDB 10

    我在 CentOS 7 中使用 yum 安装了 MariaDB SonarQube 抛出此异常 org sonar api utils MessageException Unsupported mysql version 5 5 Minim
  • 正则表达式字边界和特殊字符

    我有一个正则表达式来转义搜索字符串中的所有特殊字符 这很好用 但是我似乎无法让它与单词边界一起工作 例如 用干草堆 add or add 和针 正则表达式 gi匹配 然而正则表达式 b gi没有 关于如何实现这项工作有什么想法吗 Using
  • 无法建立 SSL 连接,如何修复我的 SSL 证书?

    我试图wget到我自己的盒子 它不能是 wget 中的内部地址 另一位开发人员是这么说的 当我得到时 我得到这个 wget http example com 2013 03 01 15 03 30 http example com Reso
  • Java中的正则表达式用于验证用户名

    我正在尝试使用 Java 中的用户名链 规则如下 长度 gt 3 有效字符 a z A Z 0 9 点 破折号和下划线 有人可以帮我解决正则表达式吗 尝试这个正则表达式 a zA Z0 9 3
  • 使用 MVVM 上下文菜单项命令绑定 WPF

    我知道这个问题已经在许多网站和 StackOverFlow 中以不同的方式被问过很多次 但我找到的所有答案都没有帮助我 准确地说 我无法理解它们并在我的应用程序中实现 所以我想从我的应用程序中添加一些代码 以便你们可以更好地帮助我 问题陈述
  • python 中 Burrows-Wheeler 的性能问题

    我试图实施布罗斯 惠勒在Python中进行转换 这是在线课程的作业之一 但我希望我已经做了一些工作才有资格寻求帮助 该算法的工作原理如下 获取一个以特殊字符 在我的例子中为 结尾的字符串 并从该字符串创建所有循环字符串 按字母顺序对所有这些
  • 为什么inline-block会导致这个div有高度呢?

    jsFiddle Demo 我似乎无法弄清楚为什么使用display inline block会导致这个 div 当包含元素被隐藏时 元素以某种方式获得高度 这不会发生在display block html div style displa
  • 在 hadoop 中并行运行作业

    我是 hadoop 新手 我已经设置了一个 2 节点集群 如何在 hadoop 中并行运行 2 个作业 当我提交作业时 它们按照 FIFO 顺序一项一项地运行 我必须并行运行这些作业 如何实现这一目标 谢谢 MRK Hadoop 可以配置多
  • 为什么 WaitForMultipleObjects 在使用多个线程句柄时会失败?

    在下面的测试程序中 每个测试线程将其句柄添加到全局TThreadList当它开始执行时 并在执行即将结束时从同一列表中删除其句柄 此外 出于测试目的 每个线程确保在主线程锁定列表之前添加其句柄 以复制其句柄并开始等待它们完成 这些线程还确保