windows系统多线程同步机制原理总结

同步问题是开发过程中遇到的重要问题之一。同步是要保证在并发执行的环境中各个控制流可以有序地执行,包括对于资源的共享或互斥访问,以及代码功能的逻辑顺序。
为了保证多线程间的同步,Windows操作系统提供了一系列的机制:事件、互斥体、信号量等等。本文主要基于对《Windows内核原理与实现》一书相关章节的整理并结合自己的理解介绍同步机制的大概实现原理,有任何不妥的地方,希望大家能够不吝指出。

Windows线程调度

我们先来简单的说以下Windows的线程调度,这是理解后续东西的基础。Windows的调度算法是一个抢占式的、支持多处理器的优先级调度算法。这种调度算法将处理器的时间分成一个个的时间片段,每个时间片段分给不同的线程去执行线程中的指令,直到时间片用完。显然,这样做使得处理器的执行不是按照一个事先知道的顺序依次进行;操作系统在调度线程时需要一个时钟中断来获得对处理器的控制权,从而引导处理器去执行操作系统想要它执行的目标线程的指令。

中断

说到Windows的线程调度是通过中断来切换线程的,那么到底什么是中断呢?我们这样想:处理器在执行指令时肯定是顺序执行指令流,那么它怎么处理一些事先无法预知、运行时才发生的事件呢?比如用户某一时刻突然敲下键盘。一种办法是处理器足够频繁地去挨个检查所有可能发生的事件是否发生了,这种方法显然很笨;另一种方法就是使用中断。
中断其实包含硬件中断和软件中断,说说硬件中断(软件中断其实是模拟的硬件中断)。硬件中断是外部设备在需要通知处理器去做一件事的时候向处理器的特定管脚(NMI和INTR)发送数据,处理器每执行完一条指令都会去检查这个管脚的状态,看看是否有中断发生。通过中断机制,处理器就不需要去挨个设备的检查了,只需要统一的检查是否发生了中断。那么,处理器在得知发生中断后,又怎么知道发生了什么中断?以及怎么去处理中断呢?
原来,每个中断都有一个中断编号,也称为中断向量。外部设备在触发处理器中断时会发生相应的中断向量。除此之外,操作系统中维护一个中断描述符表(IDT),这个表将每个中断向量与中断服务例程(用来处理该中断的一段程序)关联起来。处理器根据中断向量查询IDT,从而找到中断服务例程的地址,去执行中断服务例程,完成对中断的响应。

同步机制的实现

现在我们明白了操作系统是怎么调度线程的了,这是这种调度方式使得线程的同步有了很多不同的方式。那怎么实现呢?

1. 不依赖于线程调度的同步机制

第一种做法是对中断下手。需要申明,这种方法只对单处理器有效。单处理器情况下,导致资源争用的罪魁祸首是线程调度,它使得一个处理器分时并行地干几件事,就好像有多个处理器一样。那不让线程调度不就行了?对!前面说到了,线程调度是依靠中断实现的,那就从中断下手。处理器在处理中断时,并不是什么中断都处理,它会判断当前条件下是否需要处理某一中断。而Windows提供了一套中断级别定义方案,叫做中断请求级别(IRQL)。它使用0~31来表示优先级,数值越大,优先级越高;处理器任何时候都运行在一个级别上,且只能被更高级别的中断打断。感兴趣的同学可以去查查IRQL到底包含哪些级别,本文只说其中一个级别——DISPATCH_LEVEL,从名称中可以大致猜到这是线程调度时所在的级别。因此,如果在访问需要同步的资源之前,将处理器的运行级别提高到DISPATCH_LEVEL或更高的IRQL,这时操作系统就不会调度线程了,对单处理器而言就不存在其他线程同时访问资源的情况,也就实现了目标。

下面划重点:自旋锁我们都知道。它的实现就利用了这种方式,因此,线程在自旋等待时不会有线程切换。也正是因为不会有线程切换,省去了切换的耗时,因此它很适合预期等待时间很短的情况使用。

2. 基于线程调度的同步机制

第二种方法我们不去干涉线程调度。那么要想让不同线程能够协调起来,我们需要一个全局的东西去协调它们。这个东西就是同步对象,也称为分发器对象。无论是互斥体还是信号量还是其他什么同步方式,它们都需要针对一个确定的分发器对象。一个分发器对象有基本的两个状态:有信号和无信号状态,分发器对象初始化时为有信号状态。当一个线程执行某种同步方式时,它去查看指定分发器对象是否有信号,若有信号,该线程继续执行,同时该分发器对象的状态变为无信号;再有别的线程去查看该分发器对象时,发现状态为无信号,此时该线程进入等待状态(睡眠),操作系统的线程调度将不再调度该线程。这就实现了只能一个线程访问同一资源。

那么,当第一个线程执行完了后,分发器对象的状态重新设定为有信号后,其他在等待该分发器对象的线程又怎么知道呢?这就涉及到线程对象和分发器对象的数据结构。在线程对象和分发器对象中都有同样的一个数据成员:一个指向某一链表头节点的指针,而这个链表是一个等待块对象链表。每个等待块对象都记录了哪个线程在等待哪个对象。是的,等待块对象会同时加入到两个链表中:一个是线程对象中的链表,一个是分发器对象中的链表。
现在我们回到之前的情形,当别的线程去查看该分发器对象时,发现状态为无信号,此时实例化一个等待块对象,它记录了当前线程在等当前分发器对象,这个等待块对象都添加到了线程对象和分发器对象的链表中;当分发器对象重新变为有信号后,它会去唤醒等待块链表中记录的线程对象,此时等待的线程的状态变成延迟的就绪状态,等待操作系统线程调度器来调度。

分发器对象有很多种,具体可分为:事件、突变体、信号量、进程、线程、队列、门、定时器。有些名字听起来是不是很熟悉?是的,它们都对应着不同的同步方式:比如事件就对应同步中的事件、突变体对应互斥体…这些分发器对象在数据结构上分为两部分:对象头部和对象体。不同分发器的对象头部是一样的(对象头部的第三个数据正是等待块链表的头指针),对象体因功能不同而不同(类似于面向对象里的多态性)。对象体不同,正是与之对应的同步方式功能有所不同的本质原因。比如说突变体对象的对象体中有一个所有者概念,用于表示当前拥有该突变体对象的线程(我认为这就是互斥锁能作为递归锁的原因)。

需要说一下,这些同步方式都需要处理器提供支持。如果处理器不提供原子运算的功能,那么什么事件、信号量等等都是空谈,因为至少在对分发器对象进行判断的时候必须要保证其过程是原子操作。现代处理器会提供一些原子运算指令,比如在Inter x86指令体系中,有些运算指令加上lock前缀就可以保证其原子性,lock前缀指令使用的两个条件:

  1. 指令的目标操作数必须一个是内存操作数;
  2. 仅适用于ADD、ADC、AND、BTC、BTR、BTS、CMPXCHG、CMPXCH8B、DEC、INC、NEG、NOT、OR、SBB、SUB、XOR、XADD、XCHG。

最后总结一下,我们常见的线程同步方式,如事件、互斥体等,它们的实现都是依靠于分发器对象。操作系统通过查看分发器对象的状态,判断一个线程是等待还是执行。

windows系统多线程同步机制原理总结相关推荐

  1. 关于 Windows CE 系统中同步机制的思考

    关于 Windows® CE 系统中同步机制的思考 田海立 2006-1-18 摘要 本文讨论的话题是MSDN文档没有描述或者从它里面不容易看出来的Windows® CE线程同步的问题.既然是这样,而 ...

  2. 一文搞定c++多线程同步机制

    c++多线程同步机制 前序文章:一文搞定c++多线程 同步与互斥 现代操作系统都是多任务操作系统,通常同一时刻有大量可执行实体,则运行着的大量任务可能需要访问或使用同一资源,或者说这些任务之间具有依赖 ...

  3. Java多线程同步机制

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  4. java线程同步机制有哪些_多线程同步机制包括哪些,java线程同步机制

    多线程同步机制包括哪些什么是多线程同步机制,多线程同步机制包括:1.临界段用于实现"独占占有":2.信号量用于跟踪有限的资源:3.互斥是核心对象,可以实现不同线程之间的" ...

  5. java线程同步机制有哪些_多线程同步机制包括哪些

    多线程同步机制包括:1.Critical Section用来实现"排他性占有":2.Semaphore被用来追踪有限的资源:3.Mutex是核心对象,可以在不同的线程之间实现&qu ...

  6. Windows系统的消息机制

    第1章 Windows系统的消息机制 对诸如PowerBuilder(后文简写为PB).<

  7. Linux 多线程同步机制:互斥量、信号量、条件变量

    互斥量:互斥量提供对共享资源的保护访问,它的两种状态:lock和unlock,用来保证某段时间内只有一个线程使用共享资源,互斥量的数据类型是pthread_mutex_t 主要涉及函数:pthread ...

  8. 【转】windows平台多线程同步之Mutex的应用

    线程组成: 线程的内核对象,操作系统用来管理该线程的数据结构. 线程堆栈,它用于维护线程在执行代码时需要的所有参数和局部变量.   操作系统为每一个运行线程安排一定的CPU时间 -- 时间片.系统通过 ...

  9. java同步锁synchronized_synchronized、锁、多线程同步的原理是咋样的?

    先综述个结论:一般说的synchronized用来做多线程同步功能,其实synchronized只是提供多线程互斥,而对象的wait()和notify()方法才提供线程的同步功能.一般说synchro ...

最新文章

  1. Eclipse启动时DDMS files not found: D:\Eclipse\adt-bundle-windows-x86_64-20131030\sdk\tool
  2. 五行代码终极完美解决从IE6到Chrome所有浏览器的position:fixed;以及闪动问题
  3. 283. 移动零golang
  4. LAMP源代码编译整理
  5. jenkins发布docker项目 harbor
  6. Qt error LNK2001: unresolved external symbol
  7. Flutter进阶—自定义主题风格
  8. React中useEffect使用
  9. SignalR 跨域解决方案全面
  10. 6月第二周国内域名解析商Top10:万网份额突破21%
  11. 服务器远程开多个桌面,远程桌面多开,远程桌面多开的工具介绍,操作方法
  12. vmware tools下载缓慢问题解决
  13. MxNet创建ILSVRC2012.rec文件
  14. 照片删除格式化恢复后损坏的碎片重组修复数据恢复方法
  15. 胡润研究院发布的中国民营企业500强榜单,腾讯第一
  16. 如何调节MAC 命令行终端字体大小
  17. 【1945. 字符串转化后的各位数字之和】
  18. C++大作业--班级同学信息管理系统
  19. 避免后台进程被杀死的几种方法
  20. Python计算图片之间的相似度

热门文章

  1. 指尖江湖李忘生鸿蒙初开,剑网3指尖江湖李忘生技能搭配攻略
  2. C++中的Aggregate
  3. python爬虫统计上证指数周、月涨跌现象
  4. idea两个好用的插件-Code Reading Note与RestfulTool
  5. 计算机信息技术五大变革,信息技术及其影响教学设计
  6. 第42届ACM国际大学生程序设计竞赛 亚洲区域赛 西安站 总结
  7. 计算出1到1000以内所有不能被7整除的整数之和
  8. 那些实用有趣的网站,建议低调收藏
  9. .net framework 4.5 未指定的错误
  10. 非常经典的JAVA编程题(水仙花数)