.Net多线程编程—误用点分析
1 共享变量问题
错误写法:
所有的任务可能会共享同一个变量,所以输出结果可能会一样。
public static void Error()
{
for(int i=;i<;i++)
{
Task.Run(() => { Console.WriteLine("{0}", i); });
}
}
正确写法:
将变量i赋给局部变量temp,使得每一个任务使用不同的i值。
public static void Right()
{
for (int i = ; i < ; i++)
{
int temp = i;
Task.Run(() => { Console.WriteLine("{0}", temp); });
}
}
2 不要清理挂起任务所需资源
错误写法:
异步输出文本内容,所以在未使用完StreamReader的时候,变量sr已经离开它的作用域,调用Dispose方法。
public static void Error()
{
using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
{
Task.Run(() => { Console.WriteLine("输出:{0}",sr.ReadLine()); });
}
}
正确写法:
public static void Right()
{
using (StreamReader sr = new StreamReader(@"D:\说明.txt", Encoding.Default))
{
var task = Task.Run(() => { Console.WriteLine("输出:{0}", sr.ReadLine()); });
task.Wait();
}
}
3避免锁定this,typeof(type),string
正确的做法:定义一个object类型的私有只读字段,锁定之。
4 关于WaitHandle.WaitAll的waitHandles的数目必须小于等于64个
public static void Error()
{
ManualResetEvent[] manualEvents = new ManualResetEvent[]; try
{
for (int i = ; i < ; i++)
{
var temp = i;
Task.Run(() =>
{
manualEvents[temp] = new ManualResetEvent(false);
Console.WriteLine("{0}", temp);
manualEvents[temp].Set();
});
}
WaitHandle.WaitAll(manualEvents);
}
catch (Exception ae)
{
Console.WriteLine(ae.Message);
}
}
5 无法捕获异常的情形
try
{
var task = Task.Run(() => { throw new Exception("抛异常"); });
//如果将下面这行代码注掉,则无法抛出异常
task.Wait();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
6 是否该释放Task资源
建议调用Dispose,但不调用也不是一个严重的错误。
注意在Task任务处于某些状态时是不允许释放资源的,否则会报错。
public static void CatchException()
{
try
{
Console.WriteLine("开始");
var task = Task.Run(() =>
{
//throw new Exception("抛异常");
});
//注掉下面这行代码,观察异常结果
//task.Wait();
task.Dispose();
Console.WriteLine("结束"); }
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
7死锁演示
假设tsak1和task2都在获得第二个锁(对tsak1来说它请求的第二个锁是LockedObj2 ,而对task2来说则是LockedObj1 )之前成功获得了第一个锁,就会发生死锁。
private static readonly Object LockedObj1 = new object();
private static readonly Object LockedObj2 = new object();
public static void LockShow()
{
var task1 = Task.Run(() =>
{
lock (LockedObj1)
{
Console.WriteLine("get LockedObj1");
lock (LockedObj2)
{
Console.WriteLine("get LockedObj2....");
}
}
}); var task2 = Task.Run(() =>
{
lock (LockedObj2)
{
Console.WriteLine("get LockedObj2");
lock (LockedObj1)
{
Console.WriteLine("get LockedObj1....");
}
}
});
}
多次运行可得下面两种结果:第一个图是未发生死锁的情形,第二个图是发生死锁的情形。
8 不要调用Thread.Abort方法。
Task没有提供Abort方法,使用新的TPL(.NET 4.0以后),不会想到这个问题,一般使用CancellationToken来控制取消任务。
9 确保共享变量是安全的
反复运行,可观察到不一样的结果,下图所示。
public static void Func()
{
string s = "ASDFGH";
Parallel.Invoke(
() => { s = s.Replace("A", ""); s = s.Replace("S", "1s"); },
() => { s = s.Replace("A", ""); s = s.Replace("S", "2s"); },
() => { s = s.Replace("A", ""); }); Console.WriteLine(s);
}
10 处理器超额申请与申请不足
public static void Func()
{
ParallelOptions po = new ParallelOptions();
//超额申请,处理器只有4个逻辑内核,结果设置并行度为10且是个逻辑内核均在工作,等待的任务数量大于0.
po.MaxDegreeOfParallelism = ; //申请不足,处理器有4个逻辑内核,却指定并行度为3,还有一个空闲的内核没有被占用(也有可能被其他线程占用,这里假设在指定并行度为3的情况下,另一个内核空闲)
po.MaxDegreeOfParallelism = ; List<int> list = new List<int>();
Parallel.ForEach(list, po, m =>
{
//业务
});
}
-----------------------------------------------------------------------------------------
转载与引用请注明出处。
时间仓促,水平有限,如有不当之处,欢迎指正。
.Net多线程编程—误用点分析的更多相关文章
- QThread多线程编程经典案例分析
传统的图形界面应用程序都只有一个线程执行,并且一次执行一个操作.如果用户调用一个比较耗时的操作,就会冻结界面响应. 一个解决方法是按照事件处理的思路: 调用 Void QApplication::pr ...
- QThread多线程编程经典案例分析(三种方法,解释了为什么使用moveToThread的根本原因,即为了避免调用QThread::exec() )
传统的图形界面应用程序都只有一个线程执行,并且一次执行一个操作.如果用户调用一个比较耗时的操作,就会冻结界面响应. 一个解决方法是按照事件处理的思路: 调用 Void QApplication::pr ...
- Linux多线程编程之详细分析
线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步.互斥,这些东西将在本文中介绍.我见到这样一道面试题: 是否熟悉POSIX多线程 ...
- 《java多线程编程核心技术》不使用等待通知机制 实现线程间通信的 疑问分析
不使用等待通知机制 实现线程间通信的 疑问分析 2018年04月03日 17:15:08 ayf 阅读数:33 编辑 <java多线程编程核心技术>一书第三章开头,有如下案例: ...
- windows多线程编程星球(一)
以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...
- Java—多线程编程
一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存 ...
- 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- Java基础复习笔记系列 八 多线程编程
Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...
- Delphi中线程类TThread实现多线程编程1---构造、析构……
参考:http://www.cnblogs.com/rogee/archive/2010/09/20/1832053.html Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大 ...
随机推荐
- Python异常处理体系
1.Python内建异常体系结构 The class hierarchy for built-in exceptions is: BaseException +-- SystemExit +-- ...
- 编译内核启用iptables及netfilter
在Network Packet Filtering Framework(Netfilter)一节中还有两个额外的配置节——Core Netfilter Configuration(核心Netfilte ...
- svn branch 的使用
svn revision graph 中选中 "wc"(Mark current revision of your working copy.)这个选项后, 当前工作副本的版本号会 ...
- ASP.NET MVC 5 WEB API 用户验证
参考博客:ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1) 参考博客:MVC WebApi 用户验证 (2)构建ASP.NET MVC5+E ...
- Java谜题——库谜题
1.Java中的不可变对象和可变对象 (1)不可变类:当你获得这个类的实例的引用之后,你不可以改变这个实例的内容.比如:String,BigInteger,BigDecimal,还有基本数据类型的封装 ...
- 转 java.lang.ClassNotFoundException: org.apache.commons.lang.exception.NestableRuntimeException
转自:http://blog.csdn.net/zb0567/article/details/7893063 java.lang.ClassNotFoundException: org.apache. ...
- Linux 最简单的驱动程序hello world
图片驱动位置:kernel3-10/driver/misc/mediatek/imgsensor/src/mt8127/kd_sensorlist.c 例子:kernel-3.10/driver/mi ...
- Attribute name invalid for tag form according to TLD异常解决办法_gaigai_百度空间
body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...
- 内核kconfig语法及原理
语法 http://www.cnblogs.com/AP0904225/p/5967979.html 目前自己用过 一.菜单 menu "desc" endmenu 二.可配菜单 ...
- UILabel的抗压缩、抗拉伸、以及控件的约束简述
今天来说一说UILabel的约束设置问题 首先主要介绍:Priority(控件约束的优先级).Content Hugging Priority(控件抗拉伸优先级).Content Compressio ...