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
偶然看到了<高效能人士 必知铁律>这本书,我比较少看成功学,但是这本书把很多著名的成功学书籍整理出来,有时会让你耳目一新,有些观点尽管是常识,但是却加深了你对它们的理解,比如: 只要在积极 ...
随机推荐
- 201771010135 杨蓉庆《面对对象程序设计(java)》第十八周学习总结
1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设计结构: (4) 综合掌握java多线程编程模型: ...
- 存储引擎,MySQL中的数据类型及约束
存储引擎,MySQL中的数据类型及约束 一.存储引擎 1.不同的数据应该有不同的处理机制 2.mysql存储引擎 Innodb:默认的存储引擎,查询速度叫myisam慢,但是更安全 支持事务, ...
- yii2.0 ajax
2.0用的参数是_csrf token = "<?php echo \Yii::$app->request->getCsrfToken()?>", $.aj ...
- html5异步单图片多图片上传两种实现方式 后台.net mvc接收
Asp.net mvc上传多张图片后台存储 前台页面通过<file name="img">标签数组上传图片,后台根据Request.Files["img&qu ...
- 基于SILVACO ATLAS的a-IGZO薄膜晶体管二维器件仿真(02)
Silvaco的破解用了好久好久,而且之后拷了上次例子的代码,Tonyplot的输出存在报错,还是四连. 当然这个点一下还是会出图的.但是,源代码稍微改了下结构,又有报错,而且程序直接终止. go a ...
- mui下拉刷新 ios click事件无法响应问题
使用mui的事件监听事件 tap mui("#pullrefresh").on('tap', '.ulDiv', function (event) {this.click();}) ...
- VS2017创建控制台应用后,编写完代码调试正常,使用exe文件直接执行出现闪退情况解决方法。
这是因为代码中包含的相对路径的原因. 解决办法:把项目中包含的所有相对路径修改为绝对路径. (个人觉得因为直接执行exe文件,默认打开在C盘的用户目录下.) 例如: std::string DATA_ ...
- 记录我对'我们有成熟的时间复杂度为O(n)的算法得到数组中任意第k大的数'的误解
这篇博客记录我对剑指offer第2版"面试题39:数组中出现次数超过一半的数字"题解1的一句话的一个小误解,以及汇总一下涉及partition算法的相关题目. 在剑指offer第2 ...
- PTA的Python练习题(十二)-第4章-6 输出前 n 个Fibonacci数
接下来应该做到 第4章-6 输出前 n 个Fibonacci数 了 def fib(n): a,b = 0,1 for i in range(n+1): a,b = b,a+b return a n= ...
- sqlmap注入随笔记录
web7: 首先看见这道题,猜测flag在某页id上面,或者id是可以注入的. 先就是id爆破,用burpsuite抓了包,做了个0~9999的字典爆破id,发现自己猜测错了 那么就还是sql注入题了 ...