【问题标题】:How to implement Control.Invoke analog in custom type?如何在自定义类型中实现 Control.Invoke 模拟?
【发布时间】:2010-04-07 20:59:34
【问题描述】:

我需要在我的类“Invoke()”中实现与 Control.Invoke() 具有相同行为的方法。

因此,当我从与创建实例的线程不同的线程中处理我的 InvokableEntity 类的实例时,我将能够调用 invokableEntity.Invoke(delegate )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());
        }
    }
}

谢谢!

【问题讨论】:

  • 为什么这个问题(+一些好的答案)对你没有帮助?
  • 它对我不起作用,我无法获得可行的解决方案。调用总是在不同的线程中执行 =(
  • 来了,非常感谢您的关注!

标签: .net multithreading


【解决方案1】:

Control.Invoke() 使用PostMessage() API 调用发布一条消息,该消息将由主 GUI 线程的消息泵使用。

假设您在Thread#1 中创建了一个CustomProcessor 的实例,它不是一个GUI 线程,并且在创建CustomProcessor 的实例之后,Thread#1 继续进行长时间的处理操作。如果您需要InvokeThread#1 执行操作,您不想中止当前操作,最好将Thread#1 每次完成任务时将被Thread#1 消耗的工作项排队.
如果没有逻辑将新工作从其他线程排入队列并在Thread#1 内对其进行出队和处理,则它不会神奇地开箱即用。

如果您需要在没有消息泵的多个线程上使用此功能,并且自定义类型不是从Control 派生的,则可以实现消息队列或等效项。这样,创建线程将在消息/工作队列循环中度过其生命,大部分时间都在等待新的工作 - 就像您调用 Application.Run() 时 Windows 窗体应用程序中的主 GUI 线程一样。这可能不是你想要的。

【讨论】:

  • 非常感谢,您给了我精彩的解释!
【解决方案2】:

将调用从一个线程编组到另一个线程是一个相当大的技巧。需要一种机制来确保目标线程处于空闲状态,并且可以运行执行请求而不会出现任何令人讨厌的重入问题。

SynchronizationContext 类是这种机制的基类。它的默认实现实际上并不同步任何东西,它在线程池线程上运行委托目标。

Windows Forms 提供了一个可以满足您的需求的类,即 WindowsFormsSynchronizationContext 类。它依赖于 Application 类中的消息循环来提供同步。这个类的一个实例会自动安装,Application.Run() 方法会处理它。 WPF 也有一个 DispatcherSynchronizationContext。

问题是:您从未调用 Application.Run() 并且您没有运行消息循环。缺少所需的管道。没有那个消息循环,你就无法得到你想要的。

【讨论】:

  • 也谢谢您,您的解释也很有帮助,感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 2022-12-14
  • 2018-07-18
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-04
相关资源
最近更新 更多