基元同步构造
在介绍了线程的基本概念和限制的异步操作之后,提出多线程,线程池的概念,就不得不提到线程安全、基元用户模式和基元内核模式。
基元 是指可以在代码中使用的最简单的构造。应尽量使用基元用户模式构造,它们的速度要显著快于内核模式的构造。这是因为它们使用了特殊的CPU指令来协调线程。这意味着协调是在硬件中发生的,所以才这么快,所以也就意味着OS就检测不到线程在用户模式构造堵塞了。
从脑图中可以看出,按模式划分的三种模式:用户模式、内核模式、混合模式。按方式划分:阻塞、非阻塞、锁构造。
由于模式转换会带来巨大的性能损失,线程占有锁的时间通常都很短。有的锁限制只能由获得锁的线程释放锁,有的锁允许当前拥有它的线程递归地拥有锁。
混合模式的构造提供了用户模式所具有的性能优势。多个线程竞争一个构造时,混合构造通过基元内核模式的构造来提供不自旋的优势。
FCL的混合构造
- Monitor类和同步块
Monitor提供了自旋、线程所有权和递归的互斥锁,内置关键字lock支持它。
一个对象在构造时,它的同步块索引初始化为-1,表明不引用任何同步块。然后调用Enter时,CLR在数组中找到一个空白同步块,并设置对象的同步块索引,让它引用该同步块。当Exit时,检查是否有其他任何线程正在等待使用对象的同步块,没有就设置回-1。
- Barrier 类
- ReaderWriterLockSlim 类
- SemaphoreSlim
- System.Collections.Concurrent
- 双检锁
小结
代码尽量不要阻塞任何线程,执行异步计算或者I/O操作时候,将数据从一个线程交给另一个线程时候,应避免多个线程同时访问数据。同时访问数据的时候,应使用Volatile和Interlocked的方法,因为他们速度很快,而且不阻塞线程。
或者使用异步的同步构造来防止长时间占有锁,每个任务都关连一个或者多个连续任务,操作完成后,任务在线程池上继续执行,避免阻塞过久。对于I/O限制的操作,应当调用XxxAsync来完成操作。