Venot Asked:2022-06-28 21:42:40 +0000 UTC2022-06-28 21:42:40 +0000 UTC 2022-06-28 21:42:40 +0000 UTC 什么是引擎盖下的互斥锁? 772 test-and-set 是一条处理器指令,而互斥锁本身是一个正则变量,而 lock 函数在后台使用了这条指令,我理解正确吗?Linux内核中的互斥锁实现?很多人都写过这是关键内存区域的同步原语,但我想了解这是内核或其他地方的常见实现。 linux 1 个回答 Voted Best Answer Fat-Zer 2022-06-29T02:01:51Z2022-06-29T02:01:51Z 作为第一个近似值,锁定/解锁互斥锁看起来像这样(伪代码): struct mutex { atomic int is_locked; /* ... */ }; lock(struct mutex *mtx) { while(test_and_set(mtx->is_locked, 1)!=0) { wait_sleep(mtx); } } unlock(struct mutex *mtx) { is_locked = 0; wake(mtx); } test_and_set()是相应的处理器指令,它以原子方式将新值分配给变量并返回旧值,例如,在 x86 上 this 是XCHG. wait_sleep()- 挂起等待互斥锁的线程的函数。在幕后,它总是使用某种系统调用。休眠线程以等待某些事件总是发生在内核中。几乎¹关于 libpthread 的所有 Linux 变体,互斥锁都是用futex(). wake()- 唤醒至少一个等待此互斥体(如果有)的进程的函数。它也是通过内核实现的。 所以如果在入口处lock()会有,但该函数会简单地设置单位并立即返回is_locked。0如果有is_locked,1那么test_and_set()它不会改变它,而是将进程发送到等待。 常见修改 不仅为了性能,通常在实现中还经常有: 循环尝试在跳转到之前使用自旋锁获取互斥锁wait_sleep() 改为使用CAS指令TAS 在调用之前检查是否有进程在互斥体上等待wake() 我想了解这是内核或其他地方的通常实现。 大部分实现是在用户空间中(获取锁),但它也使用内核的支持(在释放锁之前休眠)。在这种情况下,实现通常会尽量减少转换到内核模式的次数。这是一个相当昂贵的操作,但没有它就不可能完全实现互斥锁。 ¹ 此处使用“实际”仅是因为否则有人将不得不制作自己的 libc 版本来反驳这一说法。
作为第一个近似值,锁定/解锁互斥锁看起来像这样(伪代码):
test_and_set()是相应的处理器指令,它以原子方式将新值分配给变量并返回旧值,例如,在 x86 上 this 是XCHG.wait_sleep()- 挂起等待互斥锁的线程的函数。在幕后,它总是使用某种系统调用。休眠线程以等待某些事件总是发生在内核中。几乎¹关于 libpthread 的所有 Linux 变体,互斥锁都是用futex().wake()- 唤醒至少一个等待此互斥体(如果有)的进程的函数。它也是通过内核实现的。所以如果在入口处
lock()会有,但该函数会简单地设置单位并立即返回is_locked。0如果有is_locked,1那么test_and_set()它不会改变它,而是将进程发送到等待。常见修改
不仅为了性能,通常在实现中还经常有:
wait_sleep()TASwake()大部分实现是在用户空间中(获取锁),但它也使用内核的支持(在释放锁之前休眠)。在这种情况下,实现通常会尽量减少转换到内核模式的次数。这是一个相当昂贵的操作,但没有它就不可能完全实现互斥锁。
¹ 此处使用“实际”仅是因为否则有人将不得不制作自己的 libc 版本来反驳这一说法。