Winforms .NET:如何在特定线程上调用委托?(ISynchronizeInvoke、Dispatcher、AsyncOperation、SynchronizationContext等)
首先请注意,这个问题没有标记或任何其他特定于GUI的内容。这是有意的,你很快就会看到 第二,对不起,如果这个问题有点长。我试图将四处飘荡的各种信息汇集在一起,以便提供有价值的信息。然而,我的问题就在“我想知道什么”下面 我的任务是最终理解.NET提供的在特定线程上调用委托的各种方法Winforms .NET:如何在特定线程上调用委托?(ISynchronizeInvoke、Dispatcher、AsyncOperation、SynchronizationContext等),winforms,wpf,.net,winapi,multithreading,system.componentmodel,synchronizationcontext,Winforms,Wpf,.net,Winapi,Multithreading,System.componentmodel,Synchronizationcontext,首先请注意,这个问题没有标记或任何其他特定于GUI的内容。这是有意的,你很快就会看到 第二,对不起,如果这个问题有点长。我试图将四处飘荡的各种信息汇集在一起,以便提供有价值的信息。然而,我的问题就在“我想知道什么”下面 我的任务是最终理解.NET提供的在特定线程上调用委托的各种方法 我想知道的是: 我正在寻找在特定线程上调用委托的最通用的方法(不是Winforms或WPF特定的) 或者,用不同的措辞:我会感兴趣的是,如果以及如何做到这一点的各种方式(如通过WPF的Dispatcher)相互利
我想知道的是:
- 我正在寻找在特定线程上调用委托的最通用的方法(不是Winforms或WPF特定的)
- 或者,用不同的措辞:我会感兴趣的是,如果以及如何做到这一点的各种方式(如通过WPF的
)相互利用;也就是说,如果有一种用于跨线程委托调用的公共机制被所有其他机制使用的话Dispatcher
我已经知道:
- 有许多课程与这个主题相关;其中:
- (在
)系统线程中
如果让我猜的话,那将是最基本的一个;虽然我不知道它到底是做什么的,也不知道它是如何使用的 - &(在
系统组件模型中
)
这些似乎是
的包装。不知道如何使用它们SynchronizationContext
- (在
)System.Windows.Forms中
的子类SynchronizationContext
- (在
中)System.ComponentModel
由Windows窗体使用。(控件类实现了这一点。如果我不得不猜测的话,我会说这个实现使用了
)WindowsFormsSynchronizationContext
- &(在
)中System.Windows.Threading
后者似乎是
的另一个子类,前者委托给它SynchronizationContext
- (在
- 有些线程有自己的消息循环和消息队列 (MSDN页面有一些介绍性的背景信息,介绍了消息循环在系统级别的工作方式,即作为Windows API的消息队列。) 我可以看到如何使用消息队列为线程实现跨线程调用。使用Windows API,您可以通过将消息放入特定线程的消息队列,该队列包含调用某个委托的指令。在该线程上运行的消息循环最终将到达该消息,并调用委托 ,线程不会自动拥有自己的消息队列。消息队列将变得可用,例如,当线程创建了一个窗口时。没有消息队列,线程没有消息循环是没有意义的 那么,当目标线程没有消息循环时,跨线程委托调用是否可能呢?比方说,在.NET控制台应用程序中?(从问题的答案来看,我认为使用控制台应用程序确实是不可能的。)
SynchronizationContext
类
首先,.NET framework不提供默认方法,即简单地将委托“发送”到任何线程,以便立即在那里执行委托。显然,这是行不通的,因为这意味着“中断”线程当时正在做的任何工作。因此,目标线程本身决定如何以及何时“接收”委托;也就是说,此功能必须由程序员提供
因此,目标线程需要某种方式“接收”委托。这可以通过许多不同的方式实现。一个简单的机制是线程总是返回到某个循环(让我们称之为“消息循环”),在那里它将查看队列。它会解决队列中的任何问题。当涉及到与UI相关的东西时,Windows本机就是这样工作的
在下面,我将演示如何为其实现消息队列和SynchronizationContext
,以及带有消息循环的线程。最后,我将演示如何在该线程上调用委托
例子: 步骤1。让我们首先创建一个
SynchronizationContext
类,该类将与目标线程的消息队列一起使用:
class QueueSyncContext : SynchronizationContext
{
private readonly ConcurrentQueue<SendOrPostCallback> queue;
public QueueSyncContext(ConcurrentQueue<SendOrPostCallback> queue)
{
this.queue = queue;
}
public override void Post(SendOrPostCallback d, object state)
{
queue.Enqueue(d);
}
// implementation for Send() omitted in this example for simplicity's sake.
}
步骤3。线程Z需要从某个地方开始:
new Thread(new ThreadStart(MainMethodOfThreadZ)).Start();
步骤4。最后,回到其他线程A,我们想向线程Z发送一个委托:
void SomeMethodOnThreadA()
{
// thread Z must be up and running before we can send delegates to it:
while (syncContextForThreadZ == null) ;
syncContextForThreadZ.Post(_ =>
{
Console.WriteLine("This will run on thread Z!");
},
null);
}
这一点的好处是,
SynchronizationContext
可以工作,无论您是否在Windows系统中
void SomeMethodOnThreadA()
{
// thread Z must be up and running before we can send delegates to it:
while (syncContextForThreadZ == null) ;
syncContextForThreadZ.Post(_ =>
{
Console.WriteLine("This will run on thread Z!");
},
null);
}