哪些阻塞操作会导致 STA 线程泵送 COM 消息?

2023-12-06

当在 STA 线程上实例化 COM 对象时,该线程通常必须实现消息泵,以便编组与其他线程之间的调用(请参阅here).

人们可以手动发送消息,或者依赖于某些事实,但不是所有的,线程阻塞操作将在等待时自动泵送 COM 相关消息。该文档通常无助于确定哪个是哪个(请参阅这个相关问题).

如何确定线程阻塞操作是否会在 STA 上泵送 COM 消息?

到目前为止的部分列表:

阻塞操作do pump*:

  • Thread.Join
  • WaitHandle.WaitOne/WaitAny/WaitAll (WaitAll但不能从 STA 线程调用)
  • GC.WaitForPendingFinalizers
  • Monitor.Enter(因此lock) - 在某些条件下
  • ReaderWriterLock
  • 阻塞收集

阻塞操作do not pump:

  • Thread.Sleep
  • Console.ReadKey(在某处读过)

*Note 诺塞拉蒂奥的回答据说即使是进行泵送的操作,也是针对非常有限的未公开的 COM 特定消息集进行的。


BlockingCollection阻塞时确实会泵送。我在回答以下问题时了解到,其中有一些关于 STA 泵送的有趣细节:

StaTaskScheduler 和 STA 线程消息泵

然而,它将泵送非常有限的未公开的 COM 特定消息集,与您列出的其他 API 相同。它不会泵送通用 Win32 消息(特殊情况是WM_TIMER,也不会被发送)。对于某些需要全功能消息循环的 STA COM 对象来说,这可能是一个问题。

如果您想尝试一下,请创建您自己的版本SynchronizationContext, 覆盖SynchronizationContext.Wait, call SetWaitNotificationRequired并在 STA 线程上安装自定义同步上下文对象。然后在里面设置断点Wait并查看哪些 API 会使其被调用。

标准泵送行为在多大程度上WaitOne实际上是有限的吗?下面是导致 UI 线程死锁的典型示例。我在这里使用 WinForms,但同样的问题也适用于 WPF:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        this.Load += (s, e) =>
        {
            Func<Task> doAsync = async () =>
            {
                await Task.Delay(2000);
            };

            var task = doAsync();
            var handle = ((IAsyncResult)task).AsyncWaitHandle;

            var startTick = Environment.TickCount;
            handle.WaitOne(4000);
            MessageBox.Show("Lapse: " + (Environment.TickCount - startTick));
        };
    }
}

尽管任务只需要 2000 毫秒即可完成,但消息框将显示约 4000 毫秒的时间流逝。

发生这种情况是因为await继续回调通过安排WindowsFormsSynchronizationContext.Post,它使用Control.BeginInvoke,这又使用PostMessage,发布一条注册的常规 Windows 消息RegisterWindowMessage。此消息不会被推送,并且handle.WaitOne超时。

如果我们使用handle.WaitOne(Timeout.Infinite),我们就会陷入经典的僵局。

现在让我们实现一个版本WaitOne具有显式泵送(并称其为WaitOneAndPump):

public static bool WaitOneAndPump(
    this WaitHandle handle, int millisecondsTimeout)
{
    var startTick = Environment.TickCount;
    var handles = new[] { handle.SafeWaitHandle.DangerousGetHandle() };

    while (true)
    {
        // wait for the handle or a message
        var timeout = (uint)(Timeout.Infinite == millisecondsTimeout ?
                Timeout.Infinite :
                Math.Max(0, millisecondsTimeout + 
                    startTick - Environment.TickCount));

        var result = MsgWaitForMultipleObjectsEx(
            1, handles,
            timeout,
            QS_ALLINPUT,
            MWMO_INPUTAVAILABLE);

        if (result == WAIT_OBJECT_0)
            return true; // handle signalled
        else if (result == WAIT_TIMEOUT)
            return false; // timed-out
        else if (result == WAIT_ABANDONED_0)
            throw new AbandonedMutexException(-1, handle);
        else if (result != WAIT_OBJECT_0 + 1)
            throw new InvalidOperationException();
        else
        {
            // a message is pending 
            if (timeout == 0)
                return false; // timed-out
            else
            {
                // do the pumping
                Application.DoEvents();
                // no more messages, raise Idle event
                Application.RaiseIdle(EventArgs.Empty);
            }
        }
    }
}

并把原来的代码改成这样:

var startTick = Environment.TickCount;
handle.WaitOneAndPump(4000);
MessageBox.Show("Lapse: " + (Environment.TickCount - startTick));

现在的时间间隔约为 2000 毫秒,因为await继续消息被泵送Application.DoEvents(),任务完成并且其句柄被发出信号。

也就是说,我绝不会建议使用类似的东西WaitOneAndPump用于生产代码(除了极少数的具体情况)。它是 UI 重入等各种问题的根源。这些问题是 Microsoft 将标准泵送行为限制为仅某些特定于 COM 的消息的原因,这对于 COM 封送至关重要。

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

哪些阻塞操作会导致 STA 线程泵送 COM 消息? 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐

  • “is None”和“== None”有什么区别

    我最近遇到了这种语法 我不知道其中的区别 如果有人能告诉我其中的区别 我将不胜感激 答案已解释here 去引用 一个类可以免费实现 比较任何它选择的方式 并且它 可以选择进行比较 没有任何意义 实际上 说得通 如果有人告诉你 实现 None
  • jQuery 实时且可排序

    我有以下静态 html ul li a href 10 Item 10 a li li a href 20 Item 20 a li li a href 30 Item 30 a li li a href 40 Item 40 a li l
  • PHP' aria-label='preg_replace 排除 PHP'> preg_replace 排除 PHP

    我使用 preg replace 用 href 标签替换文本中的关键字 我的正则表达式运行得很好 现在我的代码是 newstring2 preg replace p L preg quote match i p L ui a href cl
  • 等待杀死进程

    我正在尝试连接到 Azure AD 并且正在使用此代码 try var clientCredential new ClientCredential clientId clientSecret var authContext new Auth
  • 使用 splice 方法无限循环 javascript 循环遍历数组

    当我使用 splice 方法循环遍历数组时 页面就冻结了 看来我造成了无限循环 lib randomInt 有效 所以这不是问题 function return function string var arr string split ar
  • 正则表达式 Replace('/color[1-9]?[0-9]/g','') 在 JavaScript 中不起作用

    我需要从 JavaScript 中的字符串中删除所有出现的 color1 color99 我为此编写了一个简单的正则表达式 但由于某种原因它不起作用 gt color12 replace color 1 9 0 9 g color12 但是
  • 如何在下拉菜单中填充闪亮应用程序内子目录的 csv 文件。?

    可能重复 无法在 R闪亮中动态填充下拉菜单 我有一个闪亮的小应用程序 为用户提供一些下拉选项 我创建了一个子目录说data在包含 csv 文件的闪亮应用程序内 出现在下拉菜单中 我使用了下面的代码 但我无法访问其中的文件data子目录 On
  • Php 邮件密件抄送无法正常工作

    我正在尝试编辑此脚本以将密件抄送副本发送给自己 to your email from Server Xt lt email protected gt subject User Sent Msg msg HTMLmessage message
  • Amazon ELB 背后的 symfony2:始终信任代理数据?

    我正在 AWS 上运行 Symfony2 Web 应用程序 并使用弹性负载均衡器 在控制器方法中 我需要执行以下操作来获取请求网页的用户的 IP request gt trustProxyData clientIp request gt g
  • 在 Angular 的 innerHTML 中使用字符串插值

    我正在设计一个游戏 我正在动态地创建内部有空白的语句 并要求玩家填写空白 我需要字符串插值来记录用户的输入 但我还需要设置动态innerHTML 因为空格可以位于语句中的任何位置 我知道这听起来很模糊 这里是相关的代码示例 应用程序组件 h
  • Ruby on Rails 5.0 升级无法与 Rails 控制台或 db:migrate 一起使用

    最近从 Ruby on Rails 4 2 升级到 Ruby on Rails 5 0 后 我无法运行 rake db migrate 或rails console 我认为最好首先解决控制台错误 它似乎给出了以下更多信息错误 如果我正确理解
  • firebase auth 是否可以限制某些用户登录?

    目前我已经用firestore实现了登录功能 btnLogin addEventListener click e gt Get email and password const email txtEmail value const pass
  • 使用 Javascript 隐藏和显示下拉菜单和文本字段

    在下面的下拉菜单中 当用户选择操作否时 我希望显示下一个下拉菜单
  • 奇怪的 printf 输出[重复]

    这个问题在这里已经有答案了 我执行了以下代码 include
  • 如何在 FastAPI 中使用 WebSockets 发送和接收 XML 格式的数据?

    我正在尝试与指纹设备进行通信 实际上它通过一个发送数据websocket联系 所以 我想我可以使用以下方式与设备进行通信webscokets 这里我使用FastAPI 但它只接受JSON数据 问题是我需要处理XML数据 但是 我不知道如何发
  • 如何在打字稿中使用“useContext”?

    我正在尝试在我的项目中制作一个深色 浅色主题系统 但是我的代码遇到了一些问题 这行代码在 javascript 中运行良好 const darktheme setDarkTheme useContext ThemeContext 但是当我将
  • 构建过程后如何在 cmake 中编译其他源文件

    我在 Windows 的 cmake 中有一个项目 其中包含一个名为 database proc 的 Pro C 源文件 我的目标是从 proc 文件生成一个 C 源文件并将其添加到项目中以与其他源文件一起链接 我尝试添加自定义命令来实现此
  • 使用 matplotlib 仅显示一个子图的图例

    我在使用 matplotlib 以正确的格式显示图例时遇到问题 编辑 我在一个 2 x 2 格式的图中有 4 个子图 我只想在第一个子图上添加图例 该子图上绘制了两条线 我使用下面附加的代码得到的图例包含无尽的条目并垂直延伸到整个图中 当我
  • grep 或 sed 查找包含字符串的单词

    示例文件 blahblah 123 a site com some junk yoyoyoyo 456 a site com more junk hihohiho 123 a site org junk in the trunk lalal
  • 哪些阻塞操作会导致 STA 线程泵送 COM 消息?

    当在 STA 线程上实例化 COM 对象时 该线程通常必须实现消息泵 以便编组与其他线程之间的调用 请参阅here 人们可以手动发送消息 或者依赖于某些事实 但不是所有的 线程阻塞操作将在等待时自动泵送 COM 相关消息 该文档通常无助于确