.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是用来实现多线程编程的,这个绝大 ...
随机推荐
- protobuf python api
摘要: python中一切都可以看作类.那么如何查看每个类的API.使用ipython python protobuf 的函数在message中定义 此处所有的api说明:https://devel ...
- tcpdump的表达元
(nt: True 在以下的描述中含义为: 相应条件表达式中只含有以下所列的一个特定表达元, 此时表达式为真, 即条件得到满足) dst host host如果IPv4/v6 数据包的目的域是host ...
- 编写一个python脚本功能-备份
版本一 解决方案当我们基本完成程序的设计,我们就可以编写代码了,它是对我们的解决方案的实施.版本一例10.1 备份脚本——版本一 #!/usr/bin/python # Filename: backu ...
- SQL复习一(基础知识)
1.什么是sql SQL(structure query language)是结构化查询语言,它是对关系型数据库的操作语言.它可以应用到所有的数据库中,例如:MySQL.Oracle.SQL serv ...
- css3常用样式集锦
控制线显示0.5px .line:after{ content:""; display:block; position:absolute; width:200%; left:0; ...
- laravel database的事务函数
laravel的事务使用如下: DB::connection('gvideo')->transaction(function () use ($user_id, $video_id, $acti ...
- STM32F103 使用TIM3产生四路PWM
STM32F103 使用TIM3产生四路PWM 程序如下: /********************************************************************* ...
- CodeSmith生成实体类
1.新建一个模板,将以下代码复制进去,在属性工具栏里设置 SourceTtable和NameSpace , 点击生成即可 <%@ CodeTemplate Language="C#&q ...
- ecshop中ajax的调用原理 1
ecshop中ajax的调用原理 1:首先ecshop是如何定义ajax对象的. ecshop中的ajax对象是在js/transport.js文件中定义的.里面是ajax对象文件.声明了一个va ...
- java系列--批量处理
批量删除 批量更新 二.分页 1.基于sql语句 1).基于ROWID分页 2).基于RONUM分页 3).基于数据分析分页 2.基于结果集