• winform和wpf里必知的多线程知识


    背景: 很多小伙伴经常在群里问线程的问题,平时我经常转一些视频教程这些人不看,我就自己写个总结吧

    不过还是要注意的是,切换本来就不能太频繁,要一口气改。

    UI线程切换的核心思路是

    1,这行代码会直接修改UI的,必须放在UI线程,掌握这条你可以自己把winform的线程检查关掉,将Control类的静态属性CheckForIllegalCrossThreadCalls设为false,必须心里有数才能做此操作

    2,wpf也是如此,但是无法关闭线程检查,但是wpf的viewmodel就不需要UI线程,更新更方便,因为是内部通知的。

    一,开启一个新的任务

            var param = 123;
    
     //net4.5以后
            Task.Run(() =>
            {
                DoSomthing(param);
            });
    
            Task.Run(async () =>
            {
                await DoSomthingAsync(param);
            });
    
    //net 4.0
    
            Task.Factory.StartNew(delegate ()
            {
                DoSomthing(param);
            });
    
    //3.5
            Thread t = new Thread((ThreadStart)delegate ()
            {
                DoSomthing(param);
            });
            t.Start();
    //net 3.5 加线程池
     ThreadPool.QueueUserWorkItem((WaitCallback)delegate (Object obj)
            {
                DoSomthing(param);
            });

    后面都用Task为例

    二, 回到UI线程

    //winform
                Task.Run(() =>
                {
                    //类似sendMessage 等待发送结束
                    this.Invoke((Action)delegate ()
                    {
                        DoSomthing(param);
                    });
                   //类似postmessage 发了就跑
                    this.BeginInvoke((Action)delegate ()
                    {
                        DoSomthing(param);
                    });
                });
    
    //wpf 
                Task.Run(async () =>
                {
                    this.Dispatcher.Invoke(delegate ()
                    {
                        DoSomthing(param);
                    });
    
                    //使用异步等待任务结束
                    await this.Dispatcher.BeginInvoke((Action)delegate ()
                    {
                        DoSomthing(param);
                    });
                    //使用抛弃返回值的方式,直接过 不等待
                    _ = this.Dispatcher.BeginInvoke((Action)delegate ()
                     {
                         DoSomthing(param);
                     });
                });
    await Task.Run(async () =>
    {
       DoSomething();
    }
    //回到调用线程
    

      

    三, 高级方法

    1 使用 SynchronizationContext

                //在UI线程时记录下上下文
                var syncContext = SynchronizationContext.Current;
                Task.Run(() =>
                {
                    //使用UI线程
                    syncContext.Post(o =>
                    {
                        DoSomthing(param);
                    }, null);
                });

    2  await一个SynchronizationContext

                //在UI线程时记录下上下文
                var syncContext = SynchronizationContext.Current;
                Task.Run(() =>
                {
                    //回到UI线程
                    await  syncContext;
                    DoSomthing(param);//在UI线程中
                });

    那么如何await一个SynchronizationContext呢?

    //写个Awaiter类
    public sealed class SynchronizationContextAwaiter : INotifyCompletion
    {
        private readonly SynchronizationContext _context;
        public SynchronizationContextAwaiter(SynchronizationContext context) => 
            _context = context ?? throw new ArgumentNullException("context");
    
        public bool IsCompleted => SynchronizationContext.Current == _context;
        public void OnCompleted(Action action) => _context.Post(x => action(), null);
        public void GetResult() { }
    }
    
    
    //接下去使用awaiter类,写个扩展方法
    public static SynchronizationContextAwaiter GetAwaiter(this SynchronizationContext context)
        {
            return new SynchronizationContextAwaiter(context);
        }

    四,将三的内容整合到一个类中

    需要在UI线程初始化:

    UIThreadContext.Init();
    using Ruifei.Common.UIThread;
    using System;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Threading;
    
    public static class UIThreadContext
    {
        public static SynchronizationContext Context;
        public static Thread UIThread => uiThread;
        static Thread uiThread = null;
        public static void SendUIThread(Action action)
        {
            if (Context != null)
                Context.Send(x => action(), null);
            else
                action();
        }
    
        public static void SendUIThreadIfRequired(Action action)
        {
            Thread crt = Thread.CurrentThread;
            if (uiThread != crt)
                SendUIThread(action);
            else
                action();
        }
    
        public static void PostUIThread(Action action)
        {
            if (Context != null)
                Context.Post(x => action(), null);
            else
                action();
        }
    
        public static void PostUIThread(Func<Task> action)
        {
            if (Context != null)
                Context.Post(x => action(), null);
            else
                action();
        }
    
        public static void PostUIThreadIfRequired(Action action)
        {
            if (IsInUIThread())
                action();
            else
                PostUIThread(action);
        }
    
        public static void PostUIThreadIfRequired(Func<Task> action)
        {
            if (IsInUIThread())
                action();
            else
                PostUIThread(action);
        }
    
        public static bool IsInUIThread()
        {
            return uiThread == Thread.CurrentThread;
        }
    
        static Dispatcher dispatcher = (Application.Current != null && Application.Current.Dispatcher != null) ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;
        public async static void InvokeOnUIThread(Func<Task> action)
        {
            if (dispatcher == null || dispatcher.CheckAccess())
                await action();
            else
                await dispatcher.BeginInvoke(action);
        }
    
        public static void InvokeOnUIThread(Action action)
        {
            if (dispatcher == null || dispatcher.CheckAccess())
                action();
            else
                dispatcher.BeginInvoke(action);
        }
    
        public static void Init()
        {
            Context = SynchronizationContext.Current;
            uiThread = Thread.CurrentThread;
        }
    
        public static SynchronizationContextAwaiter GetAwaiter(this SynchronizationContext context)
        {
            return new SynchronizationContextAwaiter(context);
        }
    
        /// <summary>
        /// 切换到UI线程
        /// </summary>
        /// <returns></returns>
        public static SynchronizationContext SwitchToUIThread()
        {
            return UIThreadContext.Context;
        }
    
        /// <summary>
        /// WithoutContext
        /// </summary>
        /// <returns></returns>
        public static WaitForSwitchToNewTask SwitchToNewTask()
        {
            return new WaitForSwitchToNewTask(false);
        }
    }
    
    namespace Ruifei.Common.UIThread
    {
        public class WaitForSwitchToNewTask
        {
            bool withContext = false;
            public WaitForSwitchToNewTask(bool _with)
            {
                withContext = _with;
            }
            public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter()
            {
                return Task.Run(() => { }).ConfigureAwait(withContext).GetAwaiter();
            }
        }
    
        public sealed class SynchronizationContextAwaiter : INotifyCompletion
        {
            private readonly SynchronizationContext _context;
            public SynchronizationContextAwaiter(SynchronizationContext context) =>
                _context = context ?? throw new ArgumentNullException("context");
    
            public bool IsCompleted => SynchronizationContext.Current == _context;
            public void OnCompleted(Action action)
            {
                if (_context == null)
                {
                    action();
                }
                else
                {
                    _context.Send(x => action(), null);
                }
            }
    
            public void GetResult() { }
        }
    }
  • 相关阅读:
    数据结构第九篇——栈与递归
    c++重载(以运算符重载为主)
    (五)分数阶微分方程的解法及其适定性问题介绍
    (四)分数阶微积分
    (三)分数阶微积分
    (二)分数阶微积分
    小学教育试讲
    高中教育试讲
    【级数】 求和
    题东湖风光村
  • 原文地址:https://www.cnblogs.com/gxrsprite/p/12321759.html
Copyright © 2020-2023  润新知