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

问题描述 投票:1回答:1

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

当前的实现工作正常,在Duplex回调中我获得了STA线程的同步上下文,如下所示,并使用它回发到STA线程:

private readonly SynchronizationContext _syncContext = AsyncOperationManager.SynchronizationContext;

这一切都在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线程中保持双工回调方法执行?

c# multithreading winforms wcf callback
1个回答
5
投票

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

这意味着,获得的SynchronizationContext取决于您访问该物业的环境:

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

正如你可以阅读in the docs

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

因此,如果未设置当前线程的同步上下文,您将获得默认的自由线程SynchronizationContext实例。它将通过调用程序线程上的同步执行和SendPost回调来进行ThreadPool回调(因此“随机”工作线程会将它们接收)。

在Windows窗体应用程序中,主线程的SynchronizationContext将初始化为WindowsFormsSynchronizationContext实例。该实例将Post回调到主UI线程。

在WPF应用程序中,这将是一个DispatcherSynchronizationContext

在控制台应用程序中,主线程将没有SynchronizationContext。因此,我上面提到的自由线程选项开始了,所以你得到一个自由线程的SynchronizationContext实例,发布到ThreadPool。这几乎解释了你观察到的行为。

如果您需要同步,则可以为控制台应用程序的主线程实现自己的线程仿射SynchronizationContext。但这并不容易。在控制台应用程序中,您没有消息循环,也没有可以管理回调队列的调度程序。你可以看看Stephen Cleary的这个great answer,了解异步SynchronizationContext。您需要手动创建“主循环”。

© www.soinside.com 2019 - 2024. All rights reserved.