本章介绍了一些轻量级的同步原语,其中有很大部分是.NET Framework 4才引入的。

System.Threading.Barrier

用于一段程序分成多个阶段,每个阶段的开始都需要之前的阶段完成。如果这段程序需要并行化。可以在每段之间采用Barrier。

还可以设置在每个阶段之间的动作。
task在Barrier中成为参与者(participant),在构造的时候要设定数量,也可以动态的增删。
异常和超时的处理可以参考代码。
相比于使用使用Task的ContinueWith方法实现多个阶段的串行,Barrier可以减少非常多的Task数量。
用完后需要Dispose
Task[] _tasks;
Barrier _barrier;
 
_tasks ];
_barrier , (barrier) ; i ; i++)
{
    _tasks[i] = Task.Factory.StartNew((num) =>
    {
        //...阶段1
        if (!_barrier.SignalAndWait(TIMEOUT))
        {
            //...
        }
        //...阶段2
        try
        {
            _barrier.SignalAndWait();
        }
        catch (BarrierPostPhaseException bppex)
        {
            //..
            break;
        }
        //...阶段3
        _barrier.SignalAndWait();
    }, i);
}

互斥锁

C#提供了lock关键字来获取一个互斥锁。lock块编译时会被替换成System.Threading.Monitor的使用。
需要注意的点有
  • lock和Monitor只能锁引用类型的实例,不要对值类型使用lock或Monitor。
  • 要避免锁定我iabuduixinag,避免跨成员或类的边界获得或释放锁。
  • 临界区中的代码应该尽量保持简单。
lock (_obj)
{
    //...
}
//编译时lock块会被替换成如下
bool lockTaken = false;
Monitor.Enter(_obj, ref lockTaken);
try
{
    //...
}
finally
{
    if (lockTaken)
    {
        Monitor.Exit(_obj);
    }
}
如果是直接使用Monitor还可以使用TryEnter来设置超时
, ref lockTaken);
    if (!lockTaken)
    {
        throw new TimeoutException(...);
    }
    //...
}
finally
{
    if (lockTaken)
    {
        Monitor.Exit(_obj);
    }
}

自旋

Monitor开销非常大。如果锁的时间非常短,自旋锁能获取更好的性能。
但是如果长时间的自旋,SpinWait会让出时间片,并触发上下文切换。这和忙等不同。
如果多个任务都需要自旋锁,那么每一个任务都应该使用自己的实例
SpinWait在单核没有实际意义,因为必然是要做上下文切换才有可能等到的。
SpinWait.SpinUntil(Func<bool> condition,int millisecondsTimeout)提供了基于自旋的等待发方案
var sl , ref lockTaken);
    if (!lockTaken)
    {
        throw new TimeoutException(...);
    }
    //....
}
finally
{
    if (lockTaken)
    {
        sl.Exit(false);
    }
}
 

System.Threading.ManualResetEventSlim

ManualResetEventSlim是ManualResetEvent的简化版。不能跨进程或跨AppDomain。
ManualResetEventSlim是一个带有两个可能状态的事件对象,设置信号(true)和取消信号(false)
利用这个可以进行通讯
使用完后需要Dispose。
private ManualResetEventSlim manualResetEvent1;
private ManualResetEventSlim manualResetEvent2;
//method1
try
{
    manualResetEvent1.Set();
    //..
}
finally
{
    manualResetEvent1.Reset();
}
//method2
try
{
    manualResetEvent2.Set();
    if (!manualResetEvent1.Wait(TIMEOUT))
    {
        throw new TimeoutException(...);
    }
    //...
}
finally
{
    // Switch to unsignaled/unset
    manualResetEvent2.Reset();
}

System.Threading.SemaphoreSlim

System.Threading.Semaphore的轻量级版本。不能跨进程或跨AppDomain。
提供一个信号量机制来限制资源的并发访问。
用完之后需要Dispose。
SemaphoreSlim _semaphore;
 
_semaphore.Wait();
try
{
    //...
}
finally
{
    _semaphore.Release();
}
 

System.Threading.CountdownEvent

CountdownEvent带有一个初始计数器,可以发出一个信号,令计数减一。调用Wait方法时会被阻塞直到计数器达到0。
用完后需要Dispose
private static CountdownEvent _countdown;
 
//Main thread
_countdown = new CountdownEvent(MIN_PATHS);
//...
try
{
    //new Task
    //...
}
finally
{
    _countdown.Dispose();
}
 
 
//Task1
try
{
    //...
}
finally
{
    _countdown.Signal();
}
 
//Task2
_countdown.Wait();
//...
 

原子操作

在并行的环境下对共享变量的一些最基本的操作都是不安全的。
把共享变量的操作都加锁,代价又太大。
System.Threading.Interlocked,为多线程的共享变量提供原子操作。
包括 递增 递减 加法 赋值 比较 读 等等。
;
Interlocked.Increment(ref total);

其中需要注意的一点,如果在32位系统下。对64位数值的读取不是原子操作。需要使用Interlocked.Read(ref long location)。64位系统不需要,直接访问就可以了。

《C#并行编程高级教程》第5章 协调数据结构 笔记的更多相关文章

  1. 【读书笔记】.Net并行编程高级教程(二)-- 任务并行

    前面一篇提到例子都是数据并行,但这并不是并行化的唯一形式,在.Net4之前,必须要创建多个线程或者线程池来利用多核技术.现在只需要使用新的Task实例就可以通过更简单的代码解决命令式任务并行问题. 1 ...

  2. 【读书笔记】.Net并行编程高级教程--Parallel

    一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控>这本书中也多次提到并发,不管是计算机 ...

  3. Net并行编程高级教程--Parallel

    Net并行编程高级教程--Parallel 一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控 ...

  4. 《C#并行编程高级教程》第9章 异步编程模型 笔记

    这个章节我个人感觉意义不大,使用现有的APM(异步编程模型)和EAP(基于时间的异步模型)就很够用了,针对WPF和WinForm其实还有一些专门用于UI更新的类. 但是出于完整性,还是将一下怎么使用. ...

  5. 《C#并行编程高级教程》第6章 PLINQ:声明式数据并行 笔记

    PLINQ这个话题好多书都写到过,这本也没有什么特别好的地方. 几个有用和有趣的点记录一下.   顺序的不确定性 用PLINQ就一定要记住并行后会导致顺序不确定的问题.解决方案就是AsOrdered或 ...

  6. 《C#并行编程高级教程》第4章 并发集合 笔记

    这一章主要介绍了System.Collections.Concurrent下的几个类. ConcurrentQueue<T> 并发队列.完全无锁,使用CAS(compare-and-swa ...

  7. 《C#并行编程高级教程》第2章 命令式编程 笔记

    Parallel.Invoke 并行执行多个方法,只有在所有方法都执行后才会返回 static void Main(string[] args){    Parallel.Invoke(    () ...

  8. 《C#并行编程高级教程》第8章 线程池 笔记

    主要的几个概念(详细最好还是看书,配合插图看)   任务是会被分配到线程上的,而这些线程都在线程池引擎下管理 线程池引擎管理着合适数量的线程池,线程从全局队列获取工作项执行. .NET4 Framew ...

  9. 《C#并行编程高级教程》第7章 VS2010任务调试 笔记

    没有什么好说的,主要是将调试模式下的Parallel Tasks窗体和Parallel Stacks窗体.折腾一下应该比看书效果好.(表示自己没有折腾过) 另外值得注意的是,主线程不是一个任务.所以主 ...

随机推荐

  1. springmvc(五)----异常处理

    总结

  2. How to: Registry settings for generating Verbose log

    Please make sure you have following registry keys set on you computer. 32-bit: HKEY_LOCAL_MACHINE\SO ...

  3. 九度OJ 朋友圈 -- 并查集

    题目地址:http://ac.jobdu.com/problem.php?pid=1526 题目描述: 假如已知有n个人和m对好友关系(存于数字r).如果两个人是直接或间接的好友(好友的好友的好友.. ...

  4. hdu 5000 Clone

    dp,用dp[i][j],表示和为i的前j个维度的种类.其中arr[i],表示第i维的最大值. 则\begin{equation} dp[i][j] = \sum_{0 \leq k \leq \mi ...

  5. selenium自动化测试(1):环境搭建

    Selenium是一款优秀的WEB自动化测试工具,它功能强大,易于使用,支持多种平台.多种浏览器和多种开发语言.这里介绍使用python+selenium进行自动化测试的一些基础知识. 在Window ...

  6. 支持HTML5新标签

    IE8/IE7/IE6支持通过document.createElement方法产生的标签,               可以利用这一特性让这些浏览器支持HTML5新标签,               ...

  7. 重新开始学习c#啦,希望能坚持下去!

    过了这么多年,还是感觉自己喜欢C#,喜欢编程,虽然自己什么技术也没有:做的项目也不算是项目:

  8. Linux主机在LNMP环境中同时运行多个PHP版本

    这次遇到的问题是,客户网站已经使用PHP5.4运行多个网站程序,但是新安装的程序需要使用PHP5.3. 从我之前的经验来看,给网站更换PHP版本,可能会带来意想不到的后果.比如,之前某客户Discuz ...

  9. 挑战Python-20160826

    给你一字典a,如a={1:1,2:2,3:3},输出字典a的key,以','链接,如‘1,2,3'.

  10. Centos 6.2上安装使用 Informix11.70 数据库

    环境要求:操作系统: Centos 6.2 32位数据库软件: iif.11.70.UC7IE.Linux-RHEL5.tar(在IBM网站上注册个帐号就可以下载,包括windows,Linux,Un ...