线程同步 SynchronizationContext 在命令行程序中创建一个ui线程承载WPF运行
1、创建一个线程作为ui线程
ui线程要求必须是STA线程
var t = new Thread(() => { }); t.SetApartmentState(ApartmentState.STA); t.Start();
2、创建一个公共的SynchronizationContext作为同步的入口
在.NET框架中,Dispatcher是一个类,它负责接收和处理特定线程的消息队列,这通常在WPF应用程序的UI线程中使用。Dispatcher.CurrentDispatcher返回与当前线程关联的Dispatcher对象。
DispatcherSynchronizationContext是SynchronizationContext的一个实现,它使用Dispatcher来排队和执行工作项。这是在WPF中使用的,以确保只有在正确的线程(通常是UI线程)上才执行UI操作。
因此,这行代码:
uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher);
创建了一个新的DispatcherSynchronizationContext实例,该实例与当前线程的Dispatcher关联。这样,当你使用uiContext.Post或uiContext.Send方法排队工作项时,它们将通过Dispatcher在正确的线程上执行。
然后,SynchronizationContext.SetSynchronizationContext(uiContext);将新创建的DispatcherSynchronizationContext设置为当前线程的同步上下文。这样,后续的异步操作可以使用这个同步上下文来排队工作项,以确保它们在正确的线程上执行。
总的来说,这些代码确保了在UI线程上执行UI操作,从而避免了多线程环境中的竞争条件和数据不一致问题。
uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher); SynchronizationContext.SetSynchronizationContext(uiContext);
3、开启消息循环
System.Windows.Threading.Dispatcher.Run() 是一个静态方法,它开始执行与当前线程关联的 Dispatcher 的事件循环。在 WPF 中,每个 UI 线程都有一个 Dispatcher,并且 Dispatcher.Run() 用于开始处理该 Dispatcher 的消息队列。
在一个典型的 WPF 应用程序中,当你启动应用程序时,主 UI 线程的 Dispatcher.Run() 方法会被自动调用,这使得主 UI 线程可以开始处理事件,例如用户输入、绘图命令等。
在你的情况下,你创建了一个新的 STA 线程并希望它能够处理 UI 事件。为了实现这一点,你需要在该线程上调用 Dispatcher.Run(),以开始处理与该线程关联的 Dispatcher 的消息队列。
注意,Dispatcher.Run() 是一个阻塞方法,这意味着它会一直运行,直到调度程序的队列被关闭(例如,通过调用 Dispatcher.BeginInvokeShutdown 或 Dispatcher.InvokeShutdown 方法)或应用程序终止。这就是为什么你通常会在线程的主循环中看到 Dispatcher.Run() 被调用,因为这意味着线程将一直存在,直到应用程序结束或调度程序队列被明确关闭。
System.Windows.Threading.Dispatcher.Run();
4、控制此线程的生命周期
uiContext.Post(state => { Dispatcher.CurrentDispatcher.InvokeShutdown(); },null);
全部代码
class Program { [STAThread] static void Main(string[] args) { SynchronizationContext uiContext = null; var t = new Thread(() => { uiContext = new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher); SynchronizationContext.SetSynchronizationContext(uiContext); System.Windows.Threading.Dispatcher.Run(); Console.WriteLine("2222"); }); t.SetApartmentState(ApartmentState.STA); t.Start(); //while (t.IsAlive) //{ // Thread.Sleep(100); //} // 在主线程上等待 UI 线程准备好 while (uiContext == null) { Thread.Sleep(100); } uiContext.Post(state => { var winTest=new WinTest(); winTest.Show(); },null); uiContext.Post(state => { Dispatcher.CurrentDispatcher.InvokeShutdown(); },null); while (true) { Thread.Sleep(1000); Console.WriteLine(111); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧