winform和wpf里必知的多线程知识
背景: 很多小伙伴经常在群里问线程的问题,平时我经常转一些视频教程这些人不看,我就自己写个总结吧
不过还是要注意的是,切换本来就不能太频繁,要一口气改。
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里必知的多线程知识的更多相关文章
- python网络爬虫,知识储备,简单爬虫的必知必会,【核心】
知识储备,简单爬虫的必知必会,[核心] 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到桌 ...
- input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has
input屏蔽历史记录 设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处 ;(function($){$.ex ...
- 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)
15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...
- 必知必会之 Java
必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...
- Java面试必知必会:基础
面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...
- Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】
前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...
- .NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)
Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一系列是使用.NET/C# ...
- c++程序员必知的几个库
c++程序员必知的几个库 1.C++各大有名库的介绍——C++标准库 2.C++各大有名库的介绍——准标准库Boost 3.C++各大有名库的介绍——GUI 4.C++各大有名库的介绍——网络通信 5 ...
- 高效能人士必知铁律--note
偶然看到了<高效能人士 必知铁律>这本书,我比较少看成功学,但是这本书把很多著名的成功学书籍整理出来,有时会让你耳目一新,有些观点尽管是常识,但是却加深了你对它们的理解,比如: 只要在积极 ...
随机推荐
- celery task - 2
# celery task 前言 讨论一个定时任务,一般而言,需要的功能如下: 封装成对象,独立执行: 对象有一些接口,便于了解它的状态: 定时调用: 行为控制,包括重试,成功/失败回调等: 下面分别 ...
- Go之第三方日志库logrus使用
文章引用自 第三方日志库logrus使用 日志是程序中必不可少的一个环节,由于Go语言内置的日志库功能比较简洁,我们在实际开发中通常会选择使用第三方的日志库来进行开发.本文介绍了logrus这个日志库 ...
- PTA喊山
喊山 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤.呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的.原来它是彝族 ...
- 牛客小白赛4 C题
乘法逆元: 一个数a 乘上 b,在mod之后再还原成本来的数 a 这里就要用到乘法逆元,(a*b)%mod*inv(b,mod)==a ll exgcd(ll a,ll b,ll &x,ll ...
- iOS 开发之 SDWebImage 底层实现原理分析
SDWebImage 是一个比较流行的用于网络图片缓存的第三方类库.这个类库提供了一个支持缓存的图片下载器.为了方便操作者调用,它提供了很多 UI 组件的类别,例如:UIImageView.UIBut ...
- 将.NET Core Web Api发布到Linux(CentOS 7 64)
将.NET Core(2.1) Web Api发布到Linux(CentOS 7 64) 近来在学习linux相关的一些东西,然后正巧想试一下把core的应用程序发布到Linux,毕竟跨平台.尝试一下 ...
- P1067
这题没什么好说的,就是判断,需要考虑仔细一点. AC代码: #include <bits/stdc++.h> using namespace std; const int N = 712; ...
- SpringBoot2.x整合Shiro出现cors跨域问题(踩坑记录)
1. Springboot如何跨域? 最简单的方法是: 定义一个配置CorsConfig类即可(是不是简单且无耦合到令人发指) @Configuration public class CorsConf ...
- SSH 维持权限(好用)
很多时候我们拿下机器后需要维持权限,在计划任务上加入定时反弹shell这很容易被 运维人员发现,有些场景没必要用到rootkit级别的后门,我们可以尝试使用ssh后门 1.目的 长期维持机器root权 ...
- 【代码审计】VAuditDemo 前台搜索注入
在search.php中 $_GET['search']未经过任何过滤传入到$query的执行语句中