首页 > 其他 > 详细

TPL Part3 -- 数据共享

时间:2015-04-25 18:23:05      阅读:119      评论:0      收藏:0      [点我收藏+]

问题:多个Task需要操作共享变量时,会有资源竞争的问题,例如下段代码示例:

void Main()
{
 
int shared = 0;
 
Task[] tasks = new Task[10];
for (int i = 0;i < 10; i++) {
//create a new task
tasks[i] = new Task(() => {
// entera loop for 1000 balance updates
for(int j = 0;j < 1000; j++) {
//update the balance
shared++;
}
});
// startthe new task
tasks[i].Start();
}
 
Task.WaitAll(tasks);
 
Console.WriteLine(string.Format("shared : {0}",shared));
Console.ReadLine();
}


期望结果:10000,可实际结果每次都不一样(第一次为8093)。

解决方案1:隔离

即每个Task独享一个变量,最后合并结果:

void Main()
{
 
Task<int>[] tasks = new Task<int>[10];
for(int i = 0;i < 10; i++) {
//create a new task
var taskVal = 0;
tasks[i] = new Task<int>((v)=> {
int val = int.Parse(v.ToString());
// enter a loop for 1000 balance updates
for(int j = 0;j < 1000; j++) {
//update the balance
val++;
}
return val;
},taskVal);
// start the new task
tasks[i].Start();
}
 
int result = 0;
for(int i = 0;i < 10; i++) {
result+= tasks[i].Result;
}
Console.WriteLine(string.Format("result : {0}",result));
Console.ReadLine();
}


每个线程独享1个变量,进行计算返回结果,最后合并结果(在tasks[i].Result时,Task会阻塞)。

方案2:加锁

相信读者对锁已经不再陌生,它在解决资源竞争问题时是经常出现的,思路就是设定关键区域,把那部分操作变成同步的(同时只允许一个线程操作)。

锁的种类

lock :重量级锁,会带来线程切换的开销。

lock (lockObj) {
...critical region code...
}


等价于:

bool lockAcquired;
try {
Monitor.Enter(lockObj, reflockAcquired);
...critical region code...
} finally {
if (lockAcquired)Monitor.Exit(lockObj);
}


System.Threading.Interlocked:轻量级锁,会调用底层硬件特性进行优化,对于只需要操作整数++或整数--的情况很适用。常见方法:

●     Add:整数加和

●     Exchange:赋值

●     Increment:递增

●     Decrement :递减

CompareExchange<T>:比较两个数,相等则赋值

System.Threading.Mutex:可用于完成跨进程资源同步(使用命名的mutex)。

使用Synchronize特性:声明式加锁,会对类中的所有成员,方法实现锁机制,谨慎使用。

SpinLock:轻量级锁。通常对于短时间内(例如在指令级别)资源同步的情况,性能会高于monitor或SlimReaderWriterLock。

SlimReaderWriterLock:轻量级锁。优势在于读写锁分离。避免在读锁中打开写锁,会造成死锁。即便可以通过EnterUpgradeableReadLock来实现这种场景,仍然不推荐这样做。

几种并发集合

在多线程场景中,没有并发集合之前,使用集合时需要手动加锁来解决资源共享的问题,以下四种并发集合可以使我们从这种问题中release出来,在多线程场景中可以直接拿来用:

ConcurrentQueue,ConcurrentStack,ConcurrentBag,ConcurrentDictionary。

 

TPL Part3 -- 数据共享

原文:http://blog.csdn.net/lan_liang/article/details/45271541

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!