- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章.Net多线程编程(误用点分析)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1 共享变量问题 。
错误写法:
所有的任务可能会共享同一个变量,所以输出结果可能会一样.
1
2
3
4
5
6
7
|
public
static
void
Error()
{
for
(
int
i=0;i<10;i++)
{
Task.Run(() => { Console.WriteLine(
"{0}"
, i); });
}
}
|
正确写法:
将变量i赋给局部变量temp,使得每一个任务使用不同的i值.
1
2
3
4
5
6
7
8
|
public
static
void
Right()
{
for
(
int
i = 0; i < 10; i++)
{
int
temp = i;
Task.Run(() => { Console.WriteLine(
"{0}"
, temp); });
}
}
|
2 不要清理挂起任务所需资源 。
错误写法:
异步输出文本内容,所以在未使用完StreamReader的时候,变量sr已经离开它的作用域,调用Dispose方法.
1
2
3
4
5
6
7
|
public
static
void
Error()
{
using
(StreamReader sr =
new
StreamReader(
@"D:\说明.txt"
, Encoding.Default))
{
Task.Run(() => { Console.WriteLine(
"输出:{0}"
,sr.ReadLine()); });
}
}
|
正确写法:
1
2
3
4
5
6
7
8
|
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个 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
static
void
Error()
{
ManualResetEvent[] manualEvents =
new
ManualResetEvent[65];
try
{
for
(
int
i = 0; i < 65; 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 无法捕获异常的情形 。
1
2
3
4
5
6
7
8
9
10
|
try
{
var task = Task.Run(() => {
throw
new
Exception(
"抛异常"
); });
//如果将下面这行代码注掉,则无法抛出异常
task.Wait();
}
catch
(Exception ex)
{
Console.WriteLine(ex.Message);
}
|
6 是否该释放Task资源 。
建议调用Dispose,但不调用也不是一个严重的错误.
注意在Task任务处于某些状态时是不允许释放资源的,否则会报错.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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 )之前成功获得了第一个锁,就会发生死锁.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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 确保共享变量是安全的 。
反复运行,可观察到不一样的结果,下图所示.
1
2
3
4
5
6
7
8
9
|
public
static
void
Func()
{
string
s =
"ASDFGH"
;
Parallel.Invoke(
() => { s = s.Replace(
"A"
,
"1"
); s = s.Replace(
"S"
,
"1s"
); },
() => { s = s.Replace(
"A"
,
"2"
); s = s.Replace(
"S"
,
"2s"
); },
() => { s = s.Replace(
"A"
,
"3"
); });
Console.WriteLine(s);
}
|
10 处理器超额申请与申请不足 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
static
void
Func()
{
ParallelOptions po =
new
ParallelOptions();
//超额申请,处理器只有4个逻辑内核,结果设置并行度为10且是个逻辑内核均在工作,等待的任务数量大于0.
po.MaxDegreeOfParallelism = 10;
//申请不足,处理器有4个逻辑内核,却指定并行度为3,还有一个空闲的内核没有被占用(也有可能被其他线程占用,这里假设在指定并行度为3的情况下,另一个内核空闲)
po.MaxDegreeOfParallelism = 3;
List<
int
> list =
new
List<
int
>();
Parallel.ForEach(list, po, m =>
{
//业务
});
}
|
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我! 。
原文链接:http://www.cnblogs.com/hdwgxz/p/6294892.html 。
最后此篇关于.Net多线程编程(误用点分析)的文章就讲到这里了,如果你想了解更多关于.Net多线程编程(误用点分析)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在考虑如何将 tkinter Frame 和 LabelFrame 子类化以便它们位于正确的父级上时,我发现很多答案表明 super() .__init__ 在子类化时优于 BaseClass.__i
我正在编写一些实用程序,我想将它们作为函数调用。它们是通过往往不会改变的上下文和一些数据来调用的。需要对上下文进行大量耗时的处理,但是一旦完成,用它来暴露数据就相当轻量了。 这显然可以很好地映射到以下
嗨,我正在尝试找到 - 字符,然后将最左边的字符放入字符串中。在这里,我希望 FUPOPER 存储在 program_id_DB 中,但是当我运行此代码时,我的输出结果为: Character '-'
我正在尝试使用 SQL 和 PHP 创建一个登录系统。我有一个包含三个字段的标准数据库:用户名、密码和授权级别。由于某种原因,当我测试代码时,即使我使用正确的访问级别和正确的凭据,登录也会失败。在我将
我对 if 和 else 语句有疑问。 我写了下面的脚本: def questionscp(): stateanswer = raw_input('Do you want to change
我正在编写一个程序来从文件中读取数据,该文件可能采用多种格式之一(实际上是同一格式的不同版本),并且我正在使用反射为每种格式调用适当的函数。假设文件格式是在文件的第一个字节指定的数字: Class D
我花了一整天时间阅读 Fielding's famous dissertation on REST .它在 Conclusion 上说部分: REST, a novel architectural s
我正在做一些非常简单的事情,只是为了习惯 Swift(来自 objc)——我想通过使用 guard 返回链表中的所需节点。声明和 switch陈述。我显然滥用了 guard声明因为我的else子句很大
我使用的是 Visual Studio 2008 并编译了以下代码。 代码1: int* pI = new int[3]; delete pI; 代码2: int* pJ = new int[3];
我是一名优秀的程序员,十分优秀!