我需要在我的类“ Invoke()”方法中实现与 Control.Invoke()具有相同的行为。
因此,当我从与创建实例的线程不同的线程处理我的 InvokableEntity 类的实例时,我将能够调用 invokableEntity.Invoke( delegate )和委托将在创建InvokableEntity的线程实例的上下文中执行。
是的,我已经阅读了this个问题,这对我没有帮助=(
请看一下他的代码,它说明了我尝试实现事件处理程序所描述的行为( CustomProcessor_ProgressChanged 方法应该从订阅该事件的线程执行,但我不能这样做):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Windows.Forms;
namespace MultiThread
{
class Program
{
private static CustomProcessor customProcessor = new CustomProcessor();
static void Main(string[] args)
{
Console.WriteLine("Worker was run from thread: {0}", Thread.CurrentThread.ManagedThreadId);
customProcessor.ProgressChanged += new EventHandler(CustomProcessor_ProgressChanged);
Thread workerThread = new Thread(customProcessor.Process);
AsyncOperation asyncOperation = AsyncOperationManager.CreateOperation(null);
//SynchronizationContext context = SynchronizationContext.Current;
workerThread.Start(asyncOperation);
Console.ReadLine();
}
static void CustomProcessor_ProgressChanged(object sender, EventArgs e)
{
Console.WriteLine("Custom ProgressChanged was handled in thread: {0}", Thread.CurrentThread.ManagedThreadId);
}
}
class CustomProcessor
{
public event EventHandler ProgressChanged;
public void RaiseProcessChanged(object o)
{
Console.WriteLine("RaiseProgressChanged was handled in thread: {0}", Thread.CurrentThread.ManagedThreadId);
if (this.ProgressChanged != null)
{
this.ProgressChanged(this, EventArgs.Empty);
}
}
public void Process(object asyncOperation)
{
Console.WriteLine("CustomProcessor.Process method was executed in thread: {0}", Thread.CurrentThread.ManagedThreadId);
AsyncOperation asyncOperationInternal = (AsyncOperation)asyncOperation;
asyncOperationInternal.Post(this.RaiseProcessChanged, null);
//SynchronizationContext context = (SynchronizationContext) asyncOperation;
//context.Send(s => this.RaiseProcessChanged(null), null);
//this.RaiseProcessChanged(new object());
}
}
}
谢谢!
答案 0 :(得分:2)
Control.Invoke()
使用PostMessage()
API调用发布将由主GUI线程的消息泵使用的消息。
让我们假装您在CustomProcessor
中创建一个Thread#1
的实例,该实例不是GUI线程,在创建CustomProcessor
的实例后,Thread#1
会持续很长时间加工业务。如果您需要对Invoke
进行Thread#1
操作,则不希望中止当前操作,最好将每次将Thread#1
消耗的工作项排队Thread#1
完成任务
如果没有逻辑从其他线程中排列新工作并在Thread#1
内出列并对其进行处理,那么它就不会神奇地开箱即用。
如果您在没有消息泵的多个线程上需要此功能,并且自定义类型不是从Control
派生的,则可能会实现消息队列或等效消息。这样,创建线程将花费在消息/工作队列循环中,大多数时间等待新工作 - 就像调用Application.Run()
时Windows窗体应用程序中的主GUI线程一样。这可能不是你想要的。
答案 1 :(得分:2)
从一个线程到另一个线程进行编组调用是一个相当大的伎俩。所需要的是一种机制,确保目标线程处于空闲状态,并且可以运行执行请求,而不会有任何令人讨厌的重入问题的危险。
SynchronizationContext类是此类机制的基类。它的默认实现实际上不会同步任何东西,它在线程池线程上运行委托目标。
Windows Forms提供了一个可以满足您的需求的类,即WindowsFormsSynchronizationContext类。它依赖于Application类中的消息循环来提供同步。自动安装此类的实例,Application.Run()方法负责处理它。 WPF也有一个,DispatcherSynchronizationContext。
问题是:你从未调用过Application.Run()而你没有运行消息循环。缺少所需的管道。如果没有这个消息循环,你就无法得到你想要的东西。