/ Windows / 50浏览

线程同步的方式

背景

多线程在现代计算机上已经是随处可见了,保证多线程正常、高效的协调工作就显得尤为重要了。

内核也考虑到这个问题了,所以提供了一些原语来帮助达成适当的同步。

对比

原语或技术说明相关方法备注
互锁操作一种CPU的特殊指令(CPU内联函数)InterlockedIncrement/InterlockedDecrement/InterlockedAdd/InterlockedExchange/InterlockedCompareExchange常用于无锁编程中,可以在不使用软件对象的前提下执行复杂的原子操作。
分发器对象(可等待对象)此类型对象将分为有信号和无信号。它们被称为“可等待的”是因为线程 可以在这样的对象上待直至它们变成有信号。在等待期间线程不会消耗CPU周期,因为它处于等待状态。KeWaitForSingleObject/KeWaitForMultipleObjects从等待函数返回的所有值传递给NT_SUCCESS宏都返回真。
互斥量(mutant)互斥量是一种经典的对象,用于解决多个线程中的某个线程在任何时刻访问共享资源的标准问题。KeInitializeMutex/KeReleaseMutex互斥量在使用前必须初始化;使用完后必须释放互斥量。可以通过 RAII 来优雅实现。
快速互斥量快速互斥量是传统互斥量的一个替代,提供了更好的性能。ExInitializeFastMutex/ExAcquireFastMutex/ExAcquireFastMutexUnsafe(IRQL 为 APC_LEVEL)/ExReleaseFastMutex/ExReleaseFastMutexUnsafe快速互斥量不能递归地获取。这么做会造成死锁;快速互斥量被获取之后,CPU IRQL会提升到APC_LEVEL(1)。这会阻止该线程上APC的传递;快速互斥量只能无限等待—无法指定超时值。
信号量信号量的主要目标是用来限制某些东西,比如队列的长度。KeInitializeSemaphore/KeReleaseSemaphore一个最大值为一的信号量是否相当于一个互斥量?首先,这看上去 是正确的,但其实不然。信号量没有所有权,一个线程获取的信号量可以被另一个线程释放。
事件事件封装了一个布尔型的标志—要么真(有信号)要么假(无信号)。事件的主要目的是在某事发生时发出信号,提供执行流上的同 步。KeInitializeEvent/KeResetEvent/KeClearEvent事件有两种类型:通知事件(手动重置)和同步事件(自动重置)。
执行体资源适合单写多读场景的一种同步原语,是另一种特殊对象,并不属于分发器对象。ExInitializeResourceLite/ExAcquireResourceExclusiveLite/ExAcquireResourceSharedLite/ExReleaseResourceList调用获取和释放函数的先决条件是必须禁止通常的内核APC。可以调用KeEnterCriticalRegion/KeLeaveCriticalRegion来做到。
自旋锁(针对高IRQL)自旋锁是内存中的一个简单位,通过API提供原子化的测试和修改操作。当CPU想要获取自旋锁而它当前并不自由的话,CPU会一直在自旋锁上自旋,等待它被另一个CPU释放。KeAcquireSpinLock/KeReleaseSpinLock/KeAcquireSpinLockAtDpcLevel/KeReleaseSpinLockFromDpcLevel/KeAcquireInterruptSpinLock/KeReleaseInterruptSpinLock如果获取了自旋锁,千万记得在同一个函数中释放它,否则就有死 锁的风险。类似的还有 排队自旋锁。
Windows是如何区分互联网下载文件和本地文件的
Windows是如何区分互联网下载文件和本地文件的
如何低成本的获取到应用卡顿情况
如何低成本的获取到应用卡顿情况
【译】ETW 堆跟踪 – 每个分配都被记录
【译】ETW 堆跟踪 – 每个分配都被记录
【译】Wait Analysis – 寻找空闲时间
【译】Wait Analysis – 寻找空闲时间
如何通过 ETW Provider 来记录应用日志
如何通过 ETW Provider 来记录应用日志
如何通过 C++ 实时监听 ETW 事件
如何通过 C++ 实时监听 ETW 事件

0

  1. This post has no comment yet

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注