windows内核开发学习笔记四十:内核概念之同步处理

        现代操作系统中,由于多处理器、多核或者中断等各种并发(concurrency)因素的存在,同样的代码有可能被并发执行,而数据也可能被并发访问。在这种情况下,对于可能被并发访问的数据进行必要的同步(synchronization)保护是一种常见的编程实践。windows操作系统提供了多种同步机制,使得系统代码或者应用程序代码能够选择恰当的手段来保护其代码和数据。根据执行环境中的IRQL值大于APC_LEVEL或者等于PASSIVE_LEVEL,可以将同步机制分为:不依赖于线程调度的同步机制 和 基于线程调度的同步机制两大类。

        当IRQL大于APC_LEVEL时,windows提供了一些方便的保护机制,供内核自身或设备驱动程序使用。IRQL大于APC_LEVEL时典型同步机制如下:

  • 提升IRQL:根据IRQL的定义,当处理器在某个IRQL上运行时,它只能被更高IRQL的中断打断,这意味着,他不用担心低IRQL的过程会抢占当前的执行过程。这种做法在单处理器系统上可以工作的很好,但是在多处理器系统上,仅仅提升IRQL还不够,往往还要结合其他的同步机制(如自旋锁)。
  • 互锁操作:利用Intel x86处理器提供的Lock指令前缀,可以实现基本的对整数操作的保护,确保一个操作以原子方式进行。注意,这种方法只能在小粒度的数据上(可以达到64位内存单元)进行同步保护,而且是指令级的保护。
  • 无锁的单链表:链表是windows内核中被广泛使用的数据结构,windows利用64位互锁指令来实现无锁的单链表数据结构,并且可支持多核、多处理器环境。
  • 自旋锁(spin lock):自旋锁本质上是一种忙等待(busy-wait)。为了获得自旋锁,处理器不停地检测锁的状态,而不做其他的事情,直至锁的状态编成可用为止。在这种情况下,即使有线程正在等着执行,或者有APC正在排队,它们也没有机会被执行,所以,自旋锁通常用于IRQL大于等于DISPATCH_LEVEL的代码,除了标准的自旋锁,windows还实现了一些自旋锁扩展:执行体自旋锁(支持共享和独占的语义)、排队自旋锁(queued spin lock)和栈内排队自旋锁(in-stack queued spin lock)。

        一段内核代码在使用以上同步机制来保护数据时,通常会尽可能在很短的时间内解除保护,以便不妨碍其他处理器,并且让正在等待执行的线程尽快有机会得到处理器资源。

        另一类常见的同步是PASSIVE_LEVEL上线程之间的同步。当一个线程的执行条件不满足时,该线程进入等待状态,系统将控制权交给其他满足执行条件但没有得到处理器资源的线程;以后,当该线程的执行条件满足时,它又有机会继续执行。这里的执行条件正是windows提供的线程同步机制中的语义。windows定义了统一的机制来支持各种线程同步原语:分发器对象(dispatcher object),其数据结构头部为DISPATCH_HEADER。

        windows使用等待块(wait block)来描述一个正在等待分发器对象变成有信号状态。对于每个处于等待状态的线程,它有一个等待块链表,链表心中的每个节点代表该线程正在等待一个分发器对象;而对于每个分发器对象,它也有一个等待块链表,链表中的每个节点代表了正在等待该对象的一个线程。所以,当一个分发器对象变成有信号状态时,系统循环着此对象的等待块链表,就知道该解除哪个或哪些线程,即唤醒它们。线程进入等待的条件(若等待多个对象,则须指明等待任何其中之一【waitAny】或等待所有对象【waitall】及分发器对象的状态(解除一个线程或所有线程),决定了等待条件该如何被满足。

        在windows server 2003 实现了以下分发器的对象:

  • 事件(EVENT):分为事件通知对象和事件同步对象,其区别在于,当事件对象变成信号状态时,是解除正在等待该对象的线程,还是只唤醒第一个以waitany方式等待该对象的线程。
  • 突变体(mutant):突变体是windows内核中互斥体(mutex)的实现,如果突变体对象为无信号状态,则一定被某个线程占有;否则可满足任何一个线程的等待要求。突变体记录了所有者的线程信息,通常可用于实现锁。
  • 信号量(semaphone):信号量有一个计数器,用于控制最多可有多少和线程共享同一个资源,当线程计数达到预定的最大值时,信号量将变成无信号状态。
  • 队列对象(queue):这是windows内核中用于支持线程池的机制,其数据结构为KQUEUE,通常可用于控制一项任务的并发程度。它的典型用途是I/O完成端口。
  • 进程对象:windows的内核进程对象本身也是一个分发器对象,当进程对象被初始创建时,其状态为无信号;当进程结束时,其状态变成有信号。
  • 线程对象:如同进程对象一样,内核线程对象也是一个分发器对象,当线程对象被初始创建时,其状态为无信号;当进程结束时,其状态变成有信号。
  • 定时器对象:定时器对象既是一个像DPC一样的例程,也是一个可等待的分发器对象,当设定的时间到期时,定时器变成有信号状态。
  • 门对象(gate object):在windows中,门对像和门等待是线程调度器的特殊支持,它绕过了以上分发器对象同步过程中的许多步骤。唤醒一个门等待的线程几乎是以最快捷的方式进行的,线程调度器会直接将线程插入到某个处理器的就绪队列中。

        除了基于分发器对象的同步机制,Windows执行体还在此基础上实现了同步语义更为丰富的一些同步机制,包括:快速互斥体(fast mutex)、守护互斥体(guarded mutex)、执行体资源(excutive resourse)和推锁(push lock)等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jyl_sh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值