Skip to content

互斥量 (Mutual Exclusion)


用于互斥访问的内置互斥量过程(创建、加锁/解锁及销毁互斥量)。

前言

互斥(Mutual Exclusion)是一种序列化对共享资源访问的方法。如果程序员不希望一个线程访问正在被另一个线程使用的共享资源,可以使用互斥量(mutex)。

从逻辑上讲,互斥量是一把只有一把钥匙的锁:

  • 如果一个线程希望访问共享资源,必须先获取锁。

  • 一旦持有锁,该线程就可以随意使用共享资源,而无需担心其他线程访问,因为其他线程必须等待。

  • 线程使用完共享资源后,释放互斥量,从而允许其他线程访问共享资源。

互斥量保证以下三点:

  • 原子性 — 加锁互斥量是原子操作,操作系统(或线程库)保证在你加锁互斥量时,不会有其他线程同时成功加锁该互斥量。

  • 唯一性 — 如果某线程成功加锁互斥量,则可以保证在原始线程释放锁之前,没有其他线程能够加锁该互斥量。

  • 非忙等待 — 如果一个线程尝试加锁已被另一个线程加锁的互斥量,则该线程将被挂起(不消耗任何 CPU 资源),直到第二个线程释放锁。此时,第一个线程将被唤醒并继续执行,并持有互斥量的锁。

这是一种序列化共享资源访问的协议。

请注意,此协议必须在所有可能访问受保护资源的线程中强制执行(包括隐式主线程)。

互斥量功能甚至可以与分离线程(detached thread)完整配合使用(只是其处理句柄不再可通过标识符访问)。

创建与销毁互斥量

MutexCreate 创建一个互斥量,返回一个句柄标识符,用于在销毁时引用该互斥量。

使用 MutexCreate 创建的互斥量在不再需要时或程序结束前应使用 MutexDestroy 销毁。

创建

  • 语法:

declare function MutexCreate ( ) as any ptr

  • 用法:

mutexid = MutexCreate

  • 返回值:

已创建互斥量的 any ptr 句柄 (mutexid),失败时返回空指针(0)。

销毁

  • 语法:

declare sub MutexDestroy ( byval mutexid as any ptr )

  • 用法:

MutexDestroy( mutexid )

  • 参数:

mutexid

要销毁的互斥量的 any ptr 句柄。

说明

MutexCreate 的调用必须在创建任何使用它的线程之前执行(也必须在创建它的线程中使用之前执行)。

MutexDestroy 的调用必须在任何使用该互斥量的线程不再使用之后执行(也必须在销毁它的线程中最后一次使用之后执行)。

加锁与解锁互斥量

MutexLock/MutexUnlock 通过引用创建时获得的句柄标识符来加锁/解锁互斥量。

加锁

  • 语法:

declare sub MutexLock ( byval mutexid as any ptr )

  • 用法:

MutexLock( mutexid )

  • 参数:

mutexid

要加锁的互斥量的 any ptr 句柄。

解锁

  • 语法:

declare sub MutexUnlock ( byval mutexid as any ptr )

  • 用法:

MutexUnlock( mutexid )

  • 参数:

mutexid

要解锁的互斥量的 any ptr 句柄。

说明

加锁和解锁调用之间的代码称为临界区(critical section)。

尽量减少在临界区中花费的时间可以提高并发性,因为它可能会减少其他线程等待获取锁的时间。

因此,对于线程程序员而言,在可能的情况下尽量减小临界区非常重要。

伪代码示例

按照以上所有规则:

vb
'  两个线程之间互斥的原则
'  (连接线连接受序列中每个操作影响的发送方和接收方)
'
'          线程                                         其他线程
'      MUTEXLOCK(mutexID) <----------------.    .---> MUTEXLOCK(mutexID)
'      以独占方式执行某操作          .--- | ---'     以独占方式执行某操作
'      MUTEXUNLOCK(mutexID) ----------'    '--------- MUTEXUNLOCK(mutexID)

示例

上一页(Threads)的第一个示例被修改,使每个线程不再只显示一个字符("M" 或 "C"),而是显示三个字符的序列(主线程显示 "[M]",子线程显示 "(C)")。

每个线程循环中的时间片被分成三段,以帮助在线程之间交错显示。

  • 直接使用此示例:
  • 使用互斥量进行互斥访问:

参见

返回 目录

基于 FreeBASIC 官方文档翻译 如有侵权请联系我们删除
FreeBASIC 是开源项目,与微软公司无隶属关系