介绍
这是一个相当冗长的问题!在问题之前,你会找到一些背景信息,然后是简化表示的代码示例和问题。请按照您认为合适的任意顺序阅读!
背景信息
我正在为与STA COM通信的应用程序编写概念验证部分。该应用程序的这一部分要求在单线程公寓(STA)上下文中运行,以便与所述STA COM进行通信。其余应用程序在MTA上下文中运行。
当前状态
到目前为止,我想出了创建一个包含在STA中运行的Communication类的while
循环。需要传递给COM对象的工作通过ConcurrentQueue
从外部排队到Communication类中。然后在循环中将工作项出列并执行工作。
代码上下文
通信类
这是一个静态类,其中包含一个旨在以STA状态运行并检查COM是否需要完成某些工作并将工作分派给处理程序的循环。
static class Communication
{
#region Public Events
/// This event is raised when the COM object has been initialized
public static event EventHandler OnCOMInitialized;
#endregion Public Events
#region Private Members
/// Stores a reference to the COM object
private static COMType s_comObject;
/// Used to queue work that needs to be done by the COM object
private static ConcurrentQueue<WorkUnit> s_workQueue;
#endregion Private Members
#region Private Methods
/// Initializes the COM object
private static void InternalInitializeCOM()
{
s_comObject = new COMType();
if (s_comObject.Init())
{
OnCOMInitialized?.Invoke(null, EventArgs.Empty);
}
}
/// Dispatches the work unit to the correct handler
private static void HandleWork(WorkUnit work)
{
switch (work.Command)
{
case WorkCommand.Initialize:
InternalInitializeCOM();
break;
default:
break;
}
}
#endregion Private Methods
#region Public Methods
/// Starts the processing loop
public static void StartCommunication()
{
s_workQueue = new ConcurrentQueue<WorkUnit>();
while (true)
{
if (s_workQueue.TryDequeue(out var workUnit))
{
HandleWork(workUnit);
}
// [Place for a delaying logic]
}
}
/// Wraps the work unit creation for the task of Initializing the COM
public static void InitializeCOM()
{
var workUnit = new WorkUnit(
command: WorkCommand.Initialize,
arguments: null
);
s_workQueue.Enqueue(workUnit);
}
#endregion Public Methods
}
工作命令
该类描述了需要完成的工作以及可能提供的任何参数。
enum WorkCommand
{
Initialize
}
工作单元
这个枚举定义了 COM 可以执行的各种任务。
class WorkUnit
{
#region Public Properties
public WorkCommand Command { get; private set; }
public object[] Arguments { get; private set; }
#endregion Public Properties
#region Constructor
public WorkUnit(WorkCommand command, object[] arguments)
{
Command = command;
Arguments = arguments == null
? new object[0]
: arguments;
}
#endregion Constructor
}
所有者
这是一个拥有或生成与COM进行通信的Communication
类的示例,并且是在应用程序的其余部分中使用Communication
的抽象。
class COMController
{
#region Public Events
/// This event is raised when the COM object has been initialized
public event EventHandler OnInitialize;
#endregion Public Events
#region Constructor
/// Creates a new COMController instance and starts the communication
public COMController()
{
var communicationThread = new Thread(() =>
{
Communication.StartCommunication();
});
communicationThread.SetApartmentState(ApartmentState.STA);
communicationThread.Start();
Communication.OnCOMInitialized += HandleCOMInitialized;
}
#endregion Constructor
#region Private Methods
/// Handles the initialized event raised from the Communication
private void HandleCOMInitialized()
{
OnInitialize?.Invoke(this, EventArgs.Emtpy);
}
#endregion Private Methods
#region Public Methods
/// Requests that the COM object be initialized
public void Initialize()
{
Communication.InitializeCOM();
}
#endregion Public Methods
}
问题
现在,看一下 Communication.StartCommunication()
方法,具体地看这部分:
...
// [Place for a delaying logic]
...
如果用以下内容替换此行:
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
// OR
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(true);
在检查结束时 - Communication.InternalInitializeCOM()
,线程的身份貌似是MTA。
然而,如果延迟逻辑被改变为
Thread.Sleep(100);
CommunicationInternalInitializeCOM()
方法似乎在 STA 状态下执行。
检查是通过 Thread.CurrentThread.GetApartmentState()
进行的。
问题
请问有人能解释为什么 Task.Delay
会破坏 STA 状态吗?或者我在这里做错了什么?
谢谢!
感谢您抽出时间阅读这个问题!祝您拥有美好的一天!
.ConfigureAwait(false)
指示await不要捕获上下文,这通常意味着代码将在另一个线程上执行。Thread.Sleep
阻塞当前线程,与异步或公寓状态无关。 - GSerg.ConfigureAwait(true)
实现了与..(false)
相同的结果。忘记在问题中添加它了。感谢您的注意! - ful-stackz