Class Libraries and Thread Safety

  1. 线程同步是用来避免多个线程同时访问共享数据时出现冲突;
  2. 线程同步的障碍:
    • 1.极其乏味易错;
    • 2.锁严重影响性能;
    • 3.线程同步锁在同一时间点仅允许一个线程访问资源。
  3. 设计程序时应该尽可能的避免线程同步,最好避免采用static字段的共享数据;
  4. 尝试使用值类型,因为它们总是拷贝传递的,因此每个线程在自身拥有的拷贝上操作。所以当多个线程同时以只读方式访问值类型共享数据时是安全的。
  5. FCL保证所有的静态方法是线程安全的;
  6. 当一个线程构造一个对象,只有该线程拥有该对象的引用,其他线程不能访问该对象;
  7. 类型设计时应遵循的模式:确保所有的静态方法多线程安全、所有的实例方法多线程不安全;
    一个例外:如果实例方法是用于协调多线程的,那么该实例方法也应该多线程安全。如CancellationTokenSource.Cancel方法。

Primitive User-Mode and Kernel-Mode Constructs

  1. 两种原生线程同步结构:

    • 用户模式:速度很快,使用特定的CPU指令协调线程,协调工作由硬件完成。Windows系统不会检测线程是否阻塞在用户模式同步结构;
      线程池线程阻塞在用户模式同步结构不会被当成阻塞,线程池不会创建新的线程来代替临时阻塞的线程。
      采用该模式的线程会被系统抢占调度,可能导致线程被反复快速调度,从而会浪费CPU;
    • 核心模式:Windows操作系统提供,调用实现在系统内核的函数。当一个线程使用内核模式同步结构来请求其他线程持有的资源,Windows将阻塞该线程所以不会浪费CPU;
      线程在用户模式与核心模式间互相转换会严重损害性能;
    • 如果一个线程持有一个同步结构不再释放它,等待该结构的线程将永远被阻塞:
      • 活锁:如果该同步结构是用户模式,线程一直运行在CPU上;
      • 死锁:如果该同步结构是核心模式,线程被阻塞住;
    • 活锁与死锁都很糟糕,但相比之下,活锁更糟糕,因为活锁既浪费CPU又浪费内存,而死锁只浪费内存;

User-Mode Constructs

  1. 原生的用户模式结构:

    • 易变(volatile)结构:在一个简单数据类型变量上执行原子读或写操作;
    • 联锁(Interlocked)结构:在一个简单数据类型变量上执行原子读和写操作;
  2. 易变结构确认读或写操作是否原子的非常重要,它们还控制这些原子操作的时机。联锁结构执行操作要比简单的读和写操作复杂一些,它们也需要控制操作的时机;
  3. 比如一个Int64的变量如果没有正确对齐,那么当多线程读写该变量时,可能会出现只正确读取前四字节或后四字节,这就是脏读(torn read)?
  4. System.Threading.Thread.VolatileWrite(), .VolatileRead(), .MemoryBarrier()静态方法通常禁止C#编译器、JIT编译器、CPU进行优化;
  5. 当线程通过共享数据进行通信时,对最后一个值的写操作调用VolatileWrite(),对第一个值的读操作调用VolatileRead();
  6. C# volatile关键字:JIT编译器会对标记为volatile的字段的读写进行VolatileWrite()和VolatileRead()处理;
  7. 将来,C#不支持通过引用传递volatile字段到方法调用中;
  8. 现在,Interlocked.Exchange(), .CompareExchange()只支持简单值类型,将来还会提供对Object, IntPtr, Single, Double以及泛型版本的支持;
  9. SimpleSpinLock的缺陷,当锁出现竞争时,线程会不停轮转,浪费CPU资源:
    internal struct SimpleSpinLock {private Int32 m_ResourceInUse;  //0 = false (default), 1 = truepublic void Enter() {// Set the resource to in-use and if this thread// changed it from Free, then returnwhile (Interlocked.Exchange(ref m_ResourceInUse, 1) != 0) {// Black Magic goes here...}}public void Leave() {// Mark the resource as FreeThread.VolatileWrite(ref m_ResourceInUse, 0);}
    }
  10. FCL提供的System.Threading.SpinWait
  11. Thread.Sleep(),允许线程资源放弃时间片,休眠时间是近似值;
  12. Thread.Yield(),告诉Windows在当前CPU上调度其他线程。如果当前CPU上有其他线程,返回true并结束调用线程的时间片,被调度线程结束自身的时间片之后,调用线程继续。
  13. Thead.SpinWait(),线程强制自己暂停,允许超线程CPU切换到其他线程。该方法会使用特别的CPU指令,如果CPU不支持超线程,该指令被忽略;
  14. Win32 API:Sleep(), SwitchToThread(), YieldProcessor();
  15. 当集合中的每一项都需要关联锁的时候,轻量级、内存友好的SpinLock是个好东西。但是要注意不要传递它的实例,因为是值类型,传递的是拷贝;

Kernel-Mode Constructs

  1. 核心模式的同步结构比用户模式的要慢许多,因为它们由Windows操作系统协调,此外每个核心对象上的方法调用都会导致调用线程从托管代码转换到本地用户模式代码再到本地核心模式代码,然后再原路返回;
  2. 核心模式同步结构提供哪些用户模式所没有的优点:
    • 当核心模式同步结构检测到资源上出现竞争时,Windows阻塞竞争失败的线程,因此不再浪费处理器资源;
    • 核心模式同步结构可以同步本地线程和托管线程;
    • 核心模式同步结构可以同步运行在同一台机器上不同处理器上的线程;
    • 核心模式同步结构可以附上安全限制避免未经认证的帐号访问他们;
    • 线程能够被阻塞直到所有的核心模式同步结构都可用,或者任何一个可用;
    • 阻塞在核心模式同步结构上的线程可以设置一个timeout值;如果这段时间内没能获得期望的资源,那么不再阻塞以干点其他正事。
  3. 原生的核心模式结构:
    • 事件(Events):事件是有内核管理的Boolean变量。当事件为false时,线程被阻塞。有两种事件:AutoResetEventManualResetEvent
    • 信号量(Semaphore):信号量是内核管理的Int32变量。当信号量为0时,线程被阻塞;>0时,线程不被阻塞。
  4. 核心模式结构的层次结构:
      WaitHandle|--EventWaitHandle|--|--AutoResetEvent|--|--ManualResetEvent|--Semaphore|--Mutex
  5. 每个在核心模式同步结构上的方法调用都会出现完全内存保护;
  6. SimpleWaitLock vs SimpleSpinLock
    当锁上没有竞争时,SimpleWaitLockSimpleSpinLock要慢许多,因为SimpleWaitLockEnterLeave方法会强制调用线程在托管代码到核心代码之间进行来回转换;
    但是当锁上有竞争时,SimpleWaitLock不会浪费CPU资源,而SimpleSpinLock会不停的轮转CPU;
  7. AutoResetEventManualResetEventSemaphore行为比较:
    • 当多个线程在AutoResetEvent上等待时,设置事件只会让一个线程不再被阻塞;
    • 当多个线程在ManualResetEvent上等待时,设置事件会让所有线程不再被阻塞;
    • 当多个线程在Semaphore上等待时,释放信号量会让releaseCount个线程不再被阻塞(relaseCountSemaphore.Release()方法的参数)。
  8. 互斥体(Mutex)表现为一个同斥锁;
  9. Mutex很像AutoResetEvent或者Semaphore(count = 1),但有一些更复杂的逻辑:
    • 首先,Mutex对象通过查询调用线程的ID记录了哪个线程获得了它。当线程调用ReleaseMutexMutex会确认是否为同一线程;
    • 其次,Mutex维护一个递归计数指出被获得了多少次。只有当递归计数降为0时,其他线程才能获取。
  10. Mutex对象需要更多的内存,并且需要维护额外信息,所以会比较慢;
  11. 如何当一个单独的核心结构可用时调用方法?使用System.Threading.ThreadPool.RegisterWaitForSingleObject静态方法。

本章小结

本章讲述了原生的线程同步结构,首先介绍了类库和线程安全性概念,然后对线程同步模式进行了分类:用户模式与核心模式,接着详细说明了这两种同步模式的实现细节,并举例进行了对比。

转载于:https://www.cnblogs.com/bengxia/archive/2010/07/01/1768923.html

CLR Via C# 3rd 阅读摘要 -- Chapter 28 – Primitive Thread Synchronization Constructs相关推荐

  1. CLR Via C# 3rd 阅读摘要 -- Chapter 24 – Runtime Serialization

    Serialization/Deserialization Quick Start 序列化是将一个对象以及相关的对象转换成字节流的过程:反序列化就是序列化的逆过程: System.Runtime.Se ...

  2. Laravel 5文档阅读摘要

    Laravel 5项目结构分析及中文文档阅读摘要 HTTP路由 1 中间件 5 控制器 5 HTTP请求 7 HTTP 响应 8 视图 9 Service Providers 11 Service C ...

  3. 3D目标检测论文阅读摘要

    3D目标检测论文阅读摘要 2D Object Detection 的研究已经非常成熟了,代表作品有RPN系列的FasterRCNN,One Shot系列的YOLOv1-YOLOv3,这里推荐一个2D ...

  4. IDA Pro 权威指南阅读摘要1

    IDA Pro 权威指南阅读摘要1 文件加载 使用File->Open命令打开一个新文件时,会看到加载对话框. Binary File (二进制文件)是加载类型列表的最后一个选项,它是IDA加载 ...

  5. Open-Domain Question Answering相关部分论文阅读摘要

    主要内容 Open-Domain Question Answering相关部分论文阅读摘要 DrQA(Reading Wikipedia to Answer Open-Domain Questions ...

  6. 人工智能方向 - 贾扬清 - 阅读摘要

    人工智能方向 - 贾扬清 - 阅读摘要 http://daggerfs.com/ Tsinghua University:清华大学,清华 University of California, Berke ...

  7. Speech and Language Processing (3rd ed. draft) Chapter 2 ——正则表达式,文本归一化,编辑距离 阅读笔记

    前言 本章名称:REGULAR EXPRESSIONS, TEXT NORMALIZATION, EDIT DISTANCE 从 DLHLP 2020 那边了解到了这本书,开源免费,关于 Speech ...

  8. 家庭教育三书-阅读摘要

    本文由Markdown语法编辑器编辑完成. 1. 家庭教育 博客在停更了一个多月后,终于又要恢复了.之所以停更,是因为前段时间老婆生孩子了,紧接着自己又生病了,导致有1个月的时间,主要是忙于照顾孩子和 ...

  9. 《单核工作法图解》阅读摘要

    文章目录 0. 什么是单核工作法? 0.1 五项基本概念 0.2 单核和全景的节奏 0.3 单核工作法的五大原理 原理一:已经开始的任务会占据我们的思维,直到它被完成或被抛弃 原理二:多任务切换导致低 ...

最新文章

  1. JAVA逆向反混淆-追查Burpsuite的破解原理(转)
  2. tokenizer.encode() 与 tokenizer.tokenize()对比,言简意赅 转 高人讲学
  3. Windows Service 2008 R2 远程桌面关闭,自动注销的解决方法
  4. spark之4:基础指南(源自官方文档)
  5. PWA · 前后端协作 · Node | JTalk 掘金线下活动第七期
  6. C语言学习笔记---字符读取函数scanf()、gets()、fgets()
  7. react native loading动画_TypeScript for React (Native) 进阶
  8. ios 安装OpenFire
  9. SQL:postgresql查询某个字段最大值行的其他字段值
  10. sentaurus TCAD的安装与使用
  11. Flutter系列之改变CupertinoSwitch的大小
  12. 网络营销优势有哪些?
  13. 如何增强台式计算机无线网络,台式机无线网信号差怎么解决
  14. ftp服务器怎么删文件夹,删除ftp服务器文件夹
  15. 淘宝模拟登录2解决滑动验证问题
  16. 善于做“加减法”的百分点科技 成就数据智能的先行者
  17. 1.2字符类型及操作
  18. java应届生如何找工作?
  19. 一亩三分地-每日答题
  20. Bootstrap响应式Web开发(一)

热门文章

  1. Redis的两种持久化机制RDB和AOF
  2. 在soa工程中使用dubbo的步骤
  3. Centos7入侵分析:分析SSH登录日志
  4. Java匿名内部类总结
  5. gcc优化的简单说明
  6. autofac 作用域_控制作用域和生命周期
  7. 声学测试软件手机版_最新手机性能排名:小米84万分拿到第一,iQOO5Pro第五,华为?...
  8. mysql5.6最好的备份方案_Mysql 5.6迁移至PostgreSQL 9.6的实践小结
  9. STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压
  10. 隔离级别(未提交读、提交读、可重复读、可串行化)、多版本并发控制、Next-Key Locks(Record Locks、Gap Locks)