Winforms中使用的STA线程,但作为控制台应用程序执行时不使用

Dan*_*all 1 c# wcf multithreading callback winforms

我有一个程序集,该程序集在第三方的沙箱中的STA线程下运行,在该线程中,我创建了一个双工WCF客户端,该客户端需要在原始STA线程上执行方法。

当前的实现工作正常,在Duplex回调中,我按如下方式获取STA线程的同步上下文,并将其用于回发到STA线程:

private readonly SynchronizationContext _syncContext = AsyncOperationManager.SynchronizationContext;
Run Code Online (Sandbox Code Playgroud)

所有这些都在STA线程中初始化的WinForm中运行,太好了...但是我需要移动WCF双工代理,以便它在主STA线程中的类实例下运行。当我删除winform时,我最终从上述SynchronizationContext获得了一个全新的线程。

澄清:

Winforms:-

  • 在STA线程上启动WCF双工代理-ManagedThreadId = 1
  • 从服务器接收双工回调-ManagedThreadId = 5
  • 使用AsyncOperationManager.SynchronizationContext发布到回调事件方法-ManagedThreadId = 1

没有WinForm(类实例):-

  • 在STA线程上启动WCF双工代理-ManagedThreadId = 1
  • 从服务器接收双工回调-ManagedThreadId = 6
  • 使用AsyncOperationManager.SynchronizationContext发布到回调事件方法-ManagedThreadId = 11

在线程11而不是1上执行意味着我的方法无法在沙箱中正确执行,除了在winform下运行之外,变量之间的代码没有区别。有谁知道我如何在不使用winform的情况下保持STA主线程中双工回调方法的执行?

dym*_*oid 5

您正在使用AsyncOperationManager.SynchronizationContext属性获取同步上下文。该财产SynchronizationContext.Current在引擎盖下使用。

这意味着,获得的值SynchronizationContext取决于您在以下位置访问属性的环境:

  • 您正在访问该属性的线程,以及
  • 应用程序的类型。

如您在文档中所读:

默认实现是自由线程实现。

因此,如果未设置当前线程的同步上下文,则将获得默认的自由线程SynchronizationContext实例。它将Send通过在调用者线程上同步执行来进行Post回调,并回调到ThreadPool(因此“随机”工作线程将接听它们)。

在Windows Forms应用程序中,主线程SynchronizationContext将为WindowsFormsSynchronizationContext您初始化为一个实例。该实例将Post回调到主UI线程。

在WPF应用中,这将是DispatcherSynchronizationContext

在控制台应用程序中,SynchronizationContext主线程将没有任何内容。因此,我上面提到的free-threaded选项启动了,因此您获得了一个SynchronizationContext发布到的free-threaded 实例ThreadPool。这几乎可以解释您观察到的行为。

如果需要同步,则可SynchronizationContext以为控制台应用程序的主线程实现自己的线程仿射。不过,这并不容易。在控制台应用程序中,您没有消息循环,也没有可以管理回调队列的调度程序。您可以看一下Stephen Cleary提出的关于异步的一个很好的答案SynchronizationContext。但是,您将需要手动创建“主循环”。