为什么当工作线程要退出时我们需要检查IsIoPending?

2023-12-25

从win32threadpool.cpp中我们知道,工作线程在通过检查20秒超时退出之前,需要通过IsIoPending()方法检查是否有IO挂起,根据我的理解:

1、当工作线程要退出时,它必须完成它的工作并返回到线程池。

2、基于上述1,线程退出时不应该有IO等待。

所以我的问题是为什么我们需要在线程即将终止时检查 IO 挂起?或者,我们怎样才能模拟上述情况的发生呢?

RetryWaitForWork:
if (!WorkerSemaphore->Wait(AppX::IsAppXProcess() ? WorkerTimeoutAppX : WorkerTimeout))
{
    if (!IsIoPending())
    {




while (true)
{
RetryRetire:
    DWORD result = RetiredWorkerSemaphore->Wait(AppX::IsAppXProcess() ? WorkerTimeoutAppX : WorkerTimeout, FALSE);
    _ASSERTE(WAIT_OBJECT_0 == result || WAIT_TIMEOUT == result);

    if (WAIT_OBJECT_0 == result)
    {
        foundWork = true;
        counts = WorkerCounter.GetCleanCounts();
        FireEtwThreadPoolWorkerThreadRetirementStop(counts.NumActive, counts.NumRetired, GetClrInstanceId());
        goto Work;
    }

    if (!IsIoPending())
    {

https://github.com/dotnet/coreclr/blob/master/src/vm/win32threadpool.cpp https://github.com/dotnet/coreclr/blob/master/src/vm/win32threadpool.cpp


如果您搜索IsIoPending(这是我遇到不熟悉的东西时所做的第一件事),你会看到再往下看,它被调用,前面有以下注释:

// We can't exit a thread that has pending I/O - we'll "retire" it instead. https://github.com/dotnet/coreclr/blob/master/src/vm/win32threadpool.cpp#L3500

这几乎回答了你的问题。为什么在允许工作线程退出之前我们需要检查它是否有任何待处理的 I/O?嗯,因为我们无法退出具有挂起 I/O 的线程。

我想剩下的唯一问题是why not?为什么我们不能退出有待处理 I/O 的线程?为了调查这个问题,让我们看看是什么IsIoPending实际上does。在文件中进一步搜索,您会发现其实施 https://github.com/dotnet/coreclr/blob/master/src/vm/win32threadpool.cpp#L3916:

// Returns true if there is pending io on the thread.
BOOL ThreadpoolMgr::IsIoPending()
{
    CONTRACTL
    {
        NOTHROW;         
        MODE_ANY;
        GC_NOTRIGGER;
    }
    CONTRACTL_END;

#ifndef FEATURE_PAL
    int Status;
    ULONG IsIoPending;

    if (g_pufnNtQueryInformationThread)
    {
        Status =(int) (*g_pufnNtQueryInformationThread)(GetCurrentThread(),
                                          ThreadIsIoPending,
                                          &IsIoPending,
                                          sizeof(IsIoPending),
                                          NULL);


        if ((Status < 0) || IsIoPending)
            return TRUE;
        else
            return FALSE;
    }
    return TRUE;
#else
    return FALSE;
#endif // !FEATURE_PAL
}

除了确认该函数已正确命名并且它执行我们认为它执行的操作之外,该注释并没有告诉我们很多信息!但它的实施情况又如何呢?

嗯,你首先注意到的是,大多数有趣的东西都被封锁了#ifndef FEATURE_PAL条件测试。那么什么是FEATURE_PAL? PAL 代表Platform A适应Layer,它只是一种标记代码只能在 Windows 上运行的方法。如果FEATURE_PAL已定义,然后正在为操作系统编译框架other比 Windows 更重要,因此需要排除 Windows 特定的代码。这正是你在这里看到的——当FEATURE_FAL被定义,这IsIoPending函数只返回FALSE。仅当它运行在 Windows 之上时(当FEATURE_PAL is not已定义)是否需要检查 I/O 是否处于挂起状态。这非常强烈地表明,上面关于无法退出具有挂起 I/O 的线程的评论是指 Windows 操作系统的规则。

如果我们在 Windows 上运行会发生什么?对 Windows API 函数进行调用(通过全局函数指针间接调用)NtQueryInformationThread https://msdn.microsoft.com/en-us/library/windows/desktop/ms684283.aspx。第一个参数传递当前线程的句柄(GetCurrentThread()),第二个参数请求线程信息类ThreadIsIoPending,接下来的两个参数允许函数填写ULONG多变的IsIoPending(他们传递它的大小和指向它的指针)。

如果您尝试阅读文档NtQueryInformationThread,您会看到它是一个内部函数,建议应用程序:

使用公共函数GetThreadIOPendingFlag https://msdn.microsoft.com/en-us/library/windows/desktop/ms683234(v=vs.85).aspx而是获取此信息。

.NET 源代码不遵循此建议,因为该函数 (GetThreadIOPendingFlag)直到 Windows XP SP1 才被引入,并且 .NET 4(可能还有为该代码编写的旧版本)需要在 Windows 的低版本上运行。因此,他们只是调用了所有受支持的 Windows 版本上可用的内部函数。

无论如何,文档GetThreadIOPendingFlag几乎证实了它做了我们怀疑的事情:如果线程有任何待处理的 I/O 请求,则返回 true,否则返回 false。 .NET Framework 实现调用的内部函数将返回相同的信息。

现在我想我们又回到了最初的问题:为什么线程是否有挂起的 I/O 很重要?为什么我们需要在杀死它之前检查它?在 Windows 中,线程发出的 I/O 请求与该特定线程有着千丝万缕的联系。无法将此 I/O 请求或其结果数据的所有权移至另一个线程。换句话说,用户模式IRPs https://msdn.microsoft.com/en-us/library/windows/hardware/ff550694(v=vs.85).aspx不能比最初创建它们的线程寿命更长。如果线程退出,所有挂起的 I/O 将被毫不客气地取消,并且永远不会完成。因此,我们得到了原始注释中如此简洁地表述的规则:如果一个线程有挂起的 I/O,则它不能退出(因为那样 I/O 将永远不会完成并且将永远丢失)。

The GetThreadIOPendingFlag函数(或NtQueryInformationThread与类ThreadIsIoPending) 只是检查指定线程的活动 IRP 列表,看看它是否为空。如果没有待处理的 I/O 请求,则可以安全地退出线程。

工作线程可能有挂起的 I/O 请求的原因有很多,但最常见的情况是如果重叠(异步)I/O 请求 https://msdn.microsoft.com/en-us/library/windows/desktop/ms686358(v=vs.85).aspx由线程发出。在这种情况下,超时可能会在发出 I/O 完成信号之前就过去了。依赖于发出线程的异步 I/O 是 Win32 体系结构的一个基本限制,.NET Framework 的线程池实现意识到了这一限制并对其进行了解释。

可能是这个检查通常返回 false,但为了安全起见,最好明确检查它。这些是标准的防御性编程实践——对于在全球范围内运行、在各种不同条件下运行并且需要尽可能健壮的框架来说,这是非常重要的实践。

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

为什么当工作线程要退出时我们需要检查IsIoPending? 的相关文章

  • ASP.NET - 在 GridView 中显示图像和 pdf

    我想在 asp GridView 中显示 图像 列 这个想法是提供图像的缩略图以及实际尺寸图像的链接 对于某些行 这也可以是 PDF 文档 我想要 PDF 的链接 PDF 或图像存储在 SQL 数据库中 现在我在处理程序 ashx 文件中出
  • 为什么 RestSharp 反序列化两个日期的方式不同?

    我有一个返回此值的休息调用 使用 Chrome 中的 Advance Rest Client 进行测试 MyObject 22 0 ID 123456 UTC1 2013 04 19T03 12 32Z UTC2 2013 04 19T03
  • 多个 Visual Studio 项目抱怨临时文件丢失,因此无法打开。错误代码 &H80070003

    我在终端服务器上运行 Visual Studio 2010 并且已经运行了一段时间 问题相对较少 今天早上 我启动了我的电脑 在英国的长周末期间 似乎出现了以下问题 我有很多项目 但不是我的所有项目 也不是给定解决方案中的所有项目 抱怨无法
  • 字符串与 StringBuilder

    我理解之间的区别String and StringBuilder StringBuilder是可变的 但是两者之间有很大的性能差异吗 我正在开发的程序有很多大小写驱动的字符串附加 500 正在使用StringBuilder更好的选择 是的
  • 自定义 WCF DataContractSerializer

    是否可以用我自己的序列化程序替换 Windows Communication Foundation 中的 dataContractSerializer 如果可能的话 我怎样才能实现这一目标 是的 您可以提供自己的序列化器实现 默认情况下 W
  • 修饰符 async 对此项目无效

    这似乎并不是数百个具有相同错误的其他问题的重复 我把它们都看过了 发现它们是无关的 我正在制作一个小笔记应用程序 并尝试从目录中读取文件 按照 MSDN 示例 我有以下代码 但它给了我一个错误 错误 1 修饰符 async 对此无效 项目
  • 为单个方法引用大 DLL

    我想在 C 中使用大型类库 dll 中的单个方法 是否有性能或其他方面的缺点 我应该使用反射工具 读取 方法代码并将其复制粘贴到我的项目中吗 更新 硬盘空间不是问题 我的应用程序是网络应用程序 是否有性能或其他方面的缺点 唯一真正重要的是可
  • 使用 AesManaged“填充无效且无法删除”

    我正在尝试使用 AesManaged 进行简单的加密 解密 但在尝试关闭解密流时不断出现异常 这里的字符串被正确加密和解 密 然后在 Console WriteLine 打印正确的字符串后 我收到 CryptographicExceptio
  • 如何隐藏 Windows 窗体中控件的大小调整手柄?

    我有一个 UserControl 想在设计时隐藏调整大小手柄 就像 TextBoxControl 一样 它只有两个手柄 左手柄和右手柄 文本框的高度是固定的 除非你说它是多行的 在这种情况下 文本框会显示所有九个大小调整手柄 您需要实现一个
  • 发生错误。", ExceptionMessage: "提供的 'HttpContent' 实例无效

    尝试将文件添加到 http 休息调用时出现此错误 responseJson 消息 发生错误 ExceptionMessage 提供了无效的 HttpContent 实例 它确实 正在使用 多部分 参数名称 内容 异常类型 System Ar
  • 使用32位应用程序获取syswow64目录

    我正在尝试在系统目录中查找文件 问题是当使用 Environment SystemDirectory 在 x64 计算机上 我仍然获得 System32 目录 而不是 Systemwow64 目录 我需要在 x86 机器上获取 System
  • 无论表单上的焦点控件如何,如何捕获 Keys.F1?

    我使用了 KeyDown 事件和一些简单的代码 例如if e KeyCode Keys F1 捕获在表单上按下 F1 但如果表单上有一些文本框 或者表单上有一些带有 Dock Fill 的电子表格 则上面的代码将毫无用处并且不执行任何操作
  • 父窗体中的居中消息框[重复]

    这个问题在这里已经有答案了 有没有一种简单的方法可以在 net 2 0中将MessageBox居中于父窗体中 我在 C 中确实需要这个并发现中心消息框 C http bytes com topic c sharp answers 26712
  • 从 VS.NET 2008 转换到 2010 时 Windows 服务安装项目出现问题

    我正在尝试将解决方案从 VS NET 2008 转换为 2010 该解决方案包括一个 Windows 服务项目和一个安装 Windows 服务的安装项目 我在编译安装项目时遇到问题 我已经尝试按照教程从头开始几次here http msdn
  • 依赖注入的惰性解析

    我有 net 课程 我使用 Unity 作为 IOC 来解决我们的依赖关系 它尝试在开始时加载所有依赖项 Unity中有没有一种方法 设置 允许在运行时加载依赖项 还有更好的解决方案 Unity 2 0 中对 Lazy 和 IEnumera
  • StreamReader 消耗的字节数

    有没有办法知道 StreamReader 使用了流的多少字节 我有一个项目 我们需要读取一个文件 该文件具有文本标题 后跟二进制数据的开头 我最初尝试读取该文件是这样的 private int dataOffset void ReadHea
  • 在这种情况下垃圾收集器会做什么? [复制]

    这个问题在这里已经有答案了 我试图了解 GC 将如何行动的两种情况 1 有两个对象 object1 和 object2 object1 引用了 object2 object2 引用了 object1 现在 这两个对象都没有被使用 GC 可以
  • & 在 xml 文件中算作一个还是多个字符?

    我正在使用的 XML 模式具有特定的字符串字符长度 所以我可能有一个类似的字符串 Jim Mary 在 C 中是 10 个字符 但是当它写入 xml 时 它会变成 Jim amp Mary 如果 XML 模式规定字符串最多只能有 10 个字
  • .NET 迭代器包装抛出 API

    我有一个带有 API 的类 它允许我请求对象 直到它抛出一个IndexOutOfBoundsException 我想将它包装到一个迭代器中 以便能够编写更清晰的代码 但是 我需要捕获异常以停止迭代 static IEnumerable It
  • 是否有用户友好的 Log4Net 日志文件查看器? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 是否有任何第三方工具可以识别 Log4Net 日志文件结构并通过提供搜索功能等以用户友好的方式显示它 Try 色域日志查看器 https source

随机推荐

  • 将 NA 值的框添加到连续图的 ggplot 图例中

    我有一张带有图例渐变的地图 我想为 NA 值添加一个框 我的问题非常类似于this one https stackoverflow com questions 29151167 add na value to ggplot legend f
  • Github SSH 部署密钥的权限被拒绝

    我创建了一个新的存储库 能够使用 SSH 进行克隆并提交等等 但是当我尝试推送时出现以下错误 ERROR Permission to Ronin11 MealPlanr git denied to deploy key fatal Coul
  • 间歇性 SQL 异常 - 网络相关或特定于实例的错误

    我们有一个非常奇怪的间歇性问题 该问题在上个月左右开始出现 其中一些与 mssql 服务器的连接失败并出现错误 System Data SqlClient SqlException A network related or instance
  • 有什么方法可以检查变量是否是真正的 jqXHR?

    正如标题已经提到的 有没有办法检查变量是否是真正的jqXHR 我的意思是 想象的 var resource get resource if resource instanceof jqXHR do something 我试图解决的实际问题是
  • SQLAlchemy 基本问题

    我相信对于任何有 SQLAlchemy 经验的人来说 这都是基础知识 但我觉得这些文档没有什么帮助 而且我厌倦了挠头 给定两个类 class User Base tablename users id Column Integer prima
  • 包装 slf4j API

    我想将 slf4j 与 Logback 改造为遗留应用程序 好处是 遗留应用程序有自己的日志框架 所以我所要做的就是更改日志框架以记录到 slf4j 而不是 log4j 这就像做梦一样 我很高兴 直到我注意到 Logback 为每个日志事件
  • 如何让 IntelliSense 自动完成 XAML 中自定义/用户控件的枚举? [复制]

    这个问题在这里已经有答案了 可能的重复 WPF 如何在 vs2008 xaml 编辑器智能感知中显示枚举属性值 https stackoverflow com questions 419802 wpf how to display enum
  • 当我传递特定参数时,使用 ElementTree 的 iter() 解析 XML 找不到我的标签

    尝试从标签返回属性和值 逐字逐句地遵循 ElementTree 文档不会产生任何结果 没有错误 它只是运行并且不打印任何内容 如果我在没有参数的情况下运行 iter 它会打印每个标签 但如果有参数 它什么也不做 不知道发生了什么事 find
  • 使用 dockerfile 安装 Composer

    我对 docker 还很陌生 我尝试在 Dockerfile 中自动执行 Composer install 但在安装时似乎无法 cd 进入我的应用程序 出了什么问题 或者也许还有另一种更好的方法来做到这一点 我的 docker compos
  • 如何显示 MKAnnotation 的副标题 2 行文本并更改右侧按钮的图像?

    我正在查看 Apple 的 MapCallouts 示例 了解地图注释和标注 单击图钉时出现的气泡 每个注释都有坐标 标题和副标题 我想用两行显示字幕 我尝试过 NSString subtitle return Founded June 2
  • 即使用户已登录,wolkenkit 也会重定向到 Auth0

    我只是尝试按照 wolkenkit 文档使用聊天模板测试 wolkenkit 的身份验证 用户登录似乎可以工作 但即使用户已经登录 用户也会被重定向到 Auth0 客户端无需调用auth login方法 这是来自客户端的代码片段 wolke
  • 使 JEditable 适用于新元素 (.live)

    我正在使用 JEditable 插件进行就地编辑 我有一个 设置 功能 它调用 editable 所有相关课程 问题是 我有新附加的元素 我也想使其可编辑 显然 是新增的 editable 永远不会被叫到他们 换句话说 我希望获得 jque
  • Firebase 离线商店 - 查询未返回在线商店中的更改

    我在用着Firebase离线能力设置为 true let ref FIRDatabase database referenceWithPath my data child my users id scoresRef keepSynced t
  • 如何使用 javascript/jquery 动态更改图像?

    所以 我有这个http jsfiddle net ithril UjGhE 1 http jsfiddle net ithril UjGhE 1 请检查一下 我在这里尝试的是将主图像 img 标签的 src 动态更改为所单击图像的相同 sr
  • android 列表视图意图

    单击列表视图后 我无法创建意图 完成后提示错误 应用程序意外停止 请重试 public void onItemClick AdapterView
  • 缺少 Sweet Alert 的选择选项

    这可能是一个 ServiceNow 问题 但我添加了一个甜蜜警报来显示一个选择框 这样我就可以收集一个值以传递到下一条记录 但是选择框没有显示 弹出窗口只是没有框或选项 我缺少什么 截屏 选择框警报 https i stack imgur
  • Laravel 中的动态数据库连接

    我知道在 Laravel 中你可以通过在config database php文件 然后使用DB connection my conn name 但是无论如何都可以使用未在其中指定的连接config database php file 我正
  • 将类转换为字节数组 + C#

    如何在 C 中将类转换为字节数组 这是一个托管代码 因此以下代码失败 int objsize System Runtime InteropServices Marshal SizeOf objTimeSeries3D byte arr ne
  • 将 std::allocate_shared 与多态资源分配器一起使用

    我正在尝试创建共享指针std pmr monotonic buffer resource 我无法编译它 我缺少什么 https godbolt org z R9 jdju https godbolt org z R9jdju include
  • 为什么当工作线程要退出时我们需要检查IsIoPending?

    从win32threadpool cpp中我们知道 工作线程在通过检查20秒超时退出之前 需要通过IsIoPending 方法检查是否有IO挂起 根据我的理解 1 当工作线程要退出时 它必须完成它的工作并返回到线程池 2 基于上述1 线程退