“Mutex锁”究竟是什么?

7
你可以在这个链接中看到一个有趣的表格:http://norvig.com/21-days.html#answers 这张表格描述了:
Mutex lock/unlock 25纳秒
从主存中获取数据 100纳秒 纳秒是什么呢?
我很惊讶,因为mutex lock从内存中获取数据更快。如果是这样,mutex lock具体是做什么的?这个表格中的Mutex lock是什么意思?

我不明白你为什么感到惊讶。mutex锁是在数据“更改”(写入)时执行的,而fetch表示“读取”。当没有人获取mutex时,它不会执行任何操作(当“读取”操作完成时发生)。我有遗漏吗? - Nir Alfasi
2个回答

18
假设有十个人需要分享一支笔(可能是因为他们工作的公司非常缺钱)。由于他们需要用笔写长篇文档,但撰写文档的大部分时间都是思考要写什么,所以他们决定每个人可以使用笔来写一句话,并随后将其提供给其他人。
现在我们有一个问题:如果两个人都想同时使用这支笔怎么办?我们可以说两个人都可以拿起笔,但这是一支脆弱的旧笔,所以如果两个人同时拿起笔,它就会断裂。相反,我们在笔周围画了一条粉笔线。首先你把手放在粉笔线上面,然后你拿起笔。如果一个人的手在粉笔线里面,那么其他人就不允许把手放在粉笔线里面。如果两个人同时试图把手放在粉笔线上,根据这些规则只有一个人会首先进入粉笔线内部,因此另一个人必须收回手,并将其保持在粉笔线外,直到笔再次可用。
让我们将其与互斥锁相关联。互斥锁是一种保护共享资源(笔)的方式,保护的时间很短,被称为关键区域(撰写文档一句话所需的时间)。每当你想使用资源时,你都要先调用mutex_lock(将手放在粉笔线内部)。每当你完成使用资源时,你都要调用mutex_unlock(将手从粉笔线区域中拿出来)。现在来讲一下互斥锁的实现方式。互斥锁通常是使用共享内存实现的。有一个名为“mutex”的共享不透明数据对象,mutex_lockmutex_unlock函数都需要传入该对象的指针。 mutex_lock函数使用原子的测试和设置或者链接装载/条件存储指令序列(在x86上通常使用xhcg)来检查和修改互斥锁内部的数据,然后要么“获取互斥锁”——将互斥锁对象的内容设置为指示临界区已锁定以告诉其他线程,要么就必须等待。最终,线程获得互斥锁,在关键部分执行工作并调用mutex_unlock。此函数将互斥锁内部的数据设置为标记为可用,并可能唤醒正在尝试获得互斥锁的休眠线程(这取决于互斥锁的实现方式——某些mutex_lock的实现方式只会在xchg上进行紧密循环,直到互斥锁可用,因此无需mutex_unlock通知任何人)。
为什么锁定互斥锁比访问内存更快?简而言之,缓存。CPU具有可以非常快地访问的缓存,因此只要处理器可以确保没有其他处理器访问该数据,xchg操作就不需要完全访问内存。但是x86有“拥有”缓存行的概念——如果处理器0拥有一个缓存行,则想要使用该缓存行中数据的任何其他处理器都必须通过处理器0。这样,xhcg操作就不需要查看缓存以外的任何数据,而且缓存访问往往非常快,因此获取未争用的互斥锁比内存访问更快。

不过,最后一段话有一个需要注意的地方:速度优势只适用于互斥锁未被争用的情况。如果两个线程同时尝试锁定同一把互斥锁,那么运行这些线程的处理器必须进行通信并处理相关的缓存行所有权,这大大降低了互斥锁获取的速度。此外,其中一个线程必须等待另一个线程执行关键部分的代码,然后释放互斥锁,从而进一步减慢其中一个线程获取互斥锁的速度。


1
给出了非常好的例子。 (Y) - Tirth
这是一个非常好的答案。总之:缓存访问比内存访问更快,Jeff Dean在问题中引用的互斥量数字可能是针对无争议情况的。 - CppNoob

1

嗯,这只是指“LOCK”指令吗?那么,它就有意义了(25纳秒)。不过,我想知道为什么他使用了术语“Mutex lock”。 “Mutex locking”是由“LOCK”指令实现的吗? - Benjamin
我认为Mutex是“Mutual Exclusion”的简称。因此,LOCK指令可以被视为Mutex。 - Kyokook Hwang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接