互斥量 (Mutual Exclusion)
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgMtMutualExclusion
- 最后更新: 2020-11-30
用于互斥访问的内置互斥量过程(创建、加锁/解锁及销毁互斥量)。
前言
互斥(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)。
尽量减少在临界区中花费的时间可以提高并发性,因为它可能会减少其他线程等待获取锁的时间。
因此,对于线程程序员而言,在可能的情况下尽量减小临界区非常重要。
伪代码示例
按照以上所有规则:
' 两个线程之间互斥的原则
' (连接线连接受序列中每个操作影响的发送方和接收方)
'
' 线程 其他线程
' MUTEXLOCK(mutexID) <----------------. .---> MUTEXLOCK(mutexID)
' 以独占方式执行某操作 .--- | ---' 以独占方式执行某操作
' MUTEXUNLOCK(mutexID) ----------' '--------- MUTEXUNLOCK(mutexID)示例
上一页(Threads)的第一个示例被修改,使每个线程不再只显示一个字符("M" 或 "C"),而是显示三个字符的序列(主线程显示 "[M]",子线程显示 "(C)")。
每个线程循环中的时间片被分成三段,以帮助在线程之间交错显示。
- 直接使用此示例:
- 使用互斥量进行互斥访问:
参见
返回 目录