.net Control.Invoke : 工作线程将待执行方法塞进ui线程的queue ,ui线程只在自己的循环中消耗执行该queue中的方法:只允许ui线程更新ui

这篇博客深入解析了C#中工作线程如何间接更新UI控件的机制。通过控件.Invoke方法,工作线程将更新UI的函数放入UI线程的队列中,UI线程则通过循环消费队列来执行这些函数。这个过程涉及线程间通信、队列操作以及同步与异步调用的细节。
摘要由CSDN通过智能技术生成

大部分 讲 c# : 工作线程 不能直接 更新ui控件, 而 只能 间接 通过 ui线程 更新 ui控件 的 , 只 写个 控件.Invoke 的例子 , 本文 分析了 这句话 中的 “间接” 实质 是 队列、线程间交互

ui线程中消耗执行queue中的方法: InvokeMarshaledCallbacks


public class Control{
//...

private void InvokeMarshaledCallbacks()
    {
      Control.ThreadMethodEntry tme = (Control.ThreadMethodEntry) null;
      lock (this.threadCallbackList)
      {
        if (this.threadCallbackList.Count > 0) //this.threadCallbackList: 就是该queue: 队列: 容纳工作线程塞进去的函数的队列
          tme = (Control.ThreadMethodEntry) this.threadCallbackList.Dequeue();   //从该队列中弹出来一个函数(方法)
      }
      while (tme != null)  //循环消耗该队列中的元素,  (该队列中的元素是函数)
      {
        if ((object) tme.method != null)
        {
          try
          {
            if (NativeWindow.WndProcShouldBeDebuggable && !tme.synchronous)
            {
              this.InvokeMarshaledCallback(tme);//执行弹出的该函数, 此函数来自工作线程提供的
            }
            else
            {
              try
              {
                this.InvokeMarshaledCallback(tme);//执行弹出的该函数, 此方法来自工作线程提供的
              }
              catch (Exception ex)
              {
                tme.exception = ex.GetBaseException();
              }
            }
          }
          finally
          {
            tme.Complete();
            if (!NativeWindow.WndProcShouldBeDebuggable && tme.exception != null && !tme.synchronous)
              Application.OnThreadException(tme.exception);
          }
        }
        lock (this.threadCallbackList)
          tme = this.threadCallbackList.Count <= 0 ? (Control.ThreadMethodEntry) null : (Control.ThreadMethodEntry) this.threadCallbackList.Dequeue();// 从该队列中弹出下一个函数
      }
    }

//...
}

工作线程 通过 控件.Invoke 来 间接 更新ui:
MarshaledInvoke方法是两用的, 当 ui线程调用MarshaledInvoke时 作用是启动ui主循环, 当 工作线程调用MarshaledInvoke时 作用是 塞 工作线程的ui更新函数 到 ui线程.队列

public class Contrl{
//...
//工作线程代码 基本是:  ui控件.Invoke(工作线程的ui更新函数, 参数),  
//实质是:
//Invoke方法 将    工作线程的ui更新函数  塞进 ui控件.queue 中,  
// 而 控件主循环 一直在消耗该 queue,  所以 工作线程的ui更新函数  迟早会被 ui控件主循环 执行到. 
    public object Invoke(
    Delegate method, //工作线程的ui更新的函数
    params object[] args // 参数
    )
    {
      using (new Control.MultithreadSafeCallScope())
        return this.FindMarshalingControl().MarshaledInvoke(this, method, args, true);
    }
//...
//Invoke方法主要逻辑在下面这个方法MarshaledInvoke中: 
private object MarshaledInvoke(
      Control caller,
      Delegate method, //工作线程的ui更新函数;在这个函数中,工作线程表达了自己想要怎样更新ui,比如跟新进度条等
      object[] args,
      bool synchronous)
    {
      if (!this.IsHandleCreated)
        throw new InvalidOperationException(SR.GetString("ErrorNoMarshalingThread"));
      if ((Control.ActiveXImpl) this.Properties.GetObject(Control.PropActiveXImpl) != null)
        IntSecurity.UnmanagedCode.Demand();
      bool flag = false;//当前线程是否是 ui线程;  初始假定 当前线程 不是ui线程 ,即 假定 当前线程 是 工作线程
      if (SafeNativeMethods.GetWindowThreadProcessId(new HandleRef((object) this, this.Handle), out int _) == SafeNativeMethods.GetCurrentThreadId() && synchronous)
        flag = true;// 当前线程是 ui线程
      ExecutionContext executionContext = (ExecutionContext) null;
      if (!flag)// 如果当前线程不是ui线程, 即 当前线程 是 工作线程
        executionContext = ExecutionContext.Capture();
      Control.ThreadMethodEntry threadMethodEntry = new Control.ThreadMethodEntry(caller, this, method, args, synchronous, executionContext);
      lock (this)
      {
        if (this.threadCallbackList == null)
          this.threadCallbackList = new Queue();//threadCallbackList 是ui线程中的 队列, 用于容纳 工作线程的ui更新函数
      }
      lock (this.threadCallbackList)
      {
        if (Control.threadCallbackMessage == 0)
          Control.threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
        this.threadCallbackList.Enqueue((object) threadMethodEntry);// 塞 工作线程的ui更新函数 进 ui.队列
      }
      if (flag)
        this.InvokeMarshaledCallbacks();// 如果当前线程是ui线程, 则 启动ui线程主循环
      else//如果当前线程是工作线程,则 发消息 给 ui线程
        UnsafeNativeMethods.PostMessage(new HandleRef((object) this, this.Handle), Control.threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
      if (!synchronous)//如果 是异步的 ; 工作线程 调用时  :::   使用 BeginInvoke :异步的, 使用 Invoke:同步的。
        return (object) threadMethodEntry;// 如果是异步的,则直接返回工作线程
      if (!threadMethodEntry.IsCompleted)//否则,是同步的,且  工作线程的ui更新函数 还没被 ui主循环 执行完成,  则 等待
        this.WaitForWaitHandle(threadMethodEntry.AsyncWaitHandle);
      return threadMethodEntry.exception == null ? threadMethodEntry.retVal : throw threadMethodEntry.exception;
    }
    //...
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ziix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值