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

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

UI线程切换的核心思路是

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

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

一,开启一个新的任务

        var param = ;

 //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() { }
}
}

winform和wpf里必知的多线程知识的更多相关文章

  1. python网络爬虫,知识储备,简单爬虫的必知必会,【核心】

    知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...

  2. input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has

    input屏蔽历史记录   设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处   ;(function($){$.ex ...

  3. 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)

    15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...

  4. 必知必会之 Java

    必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...

  5. Java面试必知必会:基础

    面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...

  6. Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】

    前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...

  7. .NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)

    Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一系列是使用.NET/C# ...

  8. c++程序员必知的几个库

    c++程序员必知的几个库 1.C++各大有名库的介绍——C++标准库 2.C++各大有名库的介绍——准标准库Boost 3.C++各大有名库的介绍——GUI 4.C++各大有名库的介绍——网络通信 5 ...

  9. 高效能人士必知铁律--note

    偶然看到了<高效能人士 必知铁律>这本书,我比较少看成功学,但是这本书把很多著名的成功学书籍整理出来,有时会让你耳目一新,有些观点尽管是常识,但是却加深了你对它们的理解,比如: 只要在积极 ...

随机推荐

  1. docker安装后启动报错

    docker安装后启动不起来: 查看日志  /var/log/message    其中有一行为:  Your kernel does not support cgroup memory limit ...

  2. 文本编辑器EditPlus的安装

  3. Abaqus脚本接口及简单应用

    目录 1.脚本接口简介 2. 宏录制 3. 宏回放 4. 宏编辑 5. 宏控制 1.脚本接口简介 Abaqus中的脚本接口(ASI)是在Python应用程序的基础上开发的,基于Abaqus中的脚本接口 ...

  4. pycharm新建Django时,遇到的坑,安装index包失败

    https://blog.csdn.net/li93675/article/details/89418097 如果在pycharm中导入django包 ,只对当前项目有效,建议使用命令pip inst ...

  5. ASP.NET Core搭建多层网站架构【15-扩展之使用Obfuscar混淆加密保护代码】

    2020/02/03, ASP.NET Core 3.1, VS2019, Obfuscar 2.2.25 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[15-扩展之使 ...

  6. 「JSOI2013」贪心的导游

    「JSOI2013」贪心的导游 传送门 多次询问区间内%一个数的最大值 我们不妨设这个数为M_sea 值域比较小所以考虑分块维护. 我们观察到对于给定的一个 \(p\) ,函数 \(y = x \% ...

  7. 【Go语言系列】1.2、GO语言简介:哪些大公司正在使用Go语言

    Go语言的强项在于它适合用来开发网络并发方面的服务,比如消息推送.监控.容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言. 1.Google 这个不用多做介绍,作为开发Go ...

  8. mysql中date与datetime的区别

    date类型可用于需要一个日期值而不需要时间部分时.MySQL 以 'YYYY-MM-DD' 格式检索与显示date值.支持的范围是 '1000-01-01' 到'9999-12-31'. datet ...

  9. webpack使用devtool :source map插件

    链接 : https://www.cnblogs.com/chris-oil/p/8856020.html

  10. pdf.js的使用(2)新的需求已经出现,怎么能够停止不前(迪迦奥特曼主题曲)哈哈哈。^_^

    来,咱们看图说事 按钮1,2是pdf.js自带的,分别对应顺时针旋转90度,逆时针旋转90度.于是乎又要我做一个旋转180度的按钮,诺!按钮3来了. 1.别怂,干!首先顺藤摸瓜,看按钮1,2的html ...