大部分 讲 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;
}
//...
}