【发布时间】:2012-06-14 10:40:35
【问题描述】:
我有一个 C# 库,它希望能够将工作发送/发布到“主”ui 线程(如果存在)。 该库可供以下人员使用:
- winforms 应用程序
- 本机应用程序(带 UI)
- 控制台应用程序(没有 UI)
在库中,我想在初始化期间捕获一些东西(A SynchronizationContext、Dispatcher、Task Scheduler 或其他东西),这将允许我(稍后)将工作发送/发布到主线程(如果主线程有这种能力——即它有一个消息泵)。例如,当且仅当主应用程序有能力让我进入主线程时,库才会在主线程上放置一些 Winforms UI。
我尝试过的事情:
- SynchronizationContext: 捕获这对于 Winforms 应用程序很好(WindowsFormsSynchronizationContext 将作为 Current SynchronizationContext 安装。这也适用于控制台应用程序——因为我可以检测到 Current SynchronizationContext 为空(因此,知道我没有能力向主线程发送/发布工作)。这里的问题是本机 UI 应用程序:它有能力(即它有一个消息泵),但是当前同步上下文为空,因此我可以'不要将它与控制台应用案例区分开来。如果我能区分,那么我可以简单地在主线程上安装一个 WindowsFormsSynchronizationContext,我很高兴。
- A Dispatcher:使用Current 捕获它会创建一个新的 SynchronizationContext。因此,在所有情况下,我都会取回一个 Dispatcher。但是,对于控制台应用程序,从后台线程使用
Dispatcher.Invoke将挂起(如预期的那样)。我可以使用Dispatcher.FromThread(如果线程不存在,它不会为线程创建调度程序)。但是本机 UI 应用程序将使用此方法返回 null Dispatcher,因此我再次陷入无法区分 UI 应用程序和控制台应用程序的问题。 - TaskScheduler:我可以使用FromCurrentSynchronizationContext。这与 SynchronizationContext 有相同的问题。 IE。在调用 FromCurrentSynchronizationContext 之前,我必须检查 Current SynchronizationContext 是否为空(控制台应用程序和本机 ui 应用程序就是这种情况)。所以,我再次无法区分原生 ui 应用程序和控制台应用程序。
当然,我可以让我的库的用户在调用我的Initialize 方法时指定它是否是 UI 应用程序,但我希望尽可能避免库用户出现这种复杂情况。
【问题讨论】:
-
我在 MFC 中使用 C# 库。这个库有 TaskScheduler.FromCurrentSynchronizationContext() 调用。当我运行 MFC 应用程序时,它会抛出异常,说“当前 SynchronizationContext 可能不能用作 TaskScheduler”。知道如何处理它吗?我没有直接在 MFC 中使用 C# 库,但我在托管 C++ 中创建了一个包装器,并且我在 MFC 应用程序中使用了这个包装器。
标签: c# winforms multithreading synchronization