我想知道互斥锁(或其他锁定实现)如何实现锁定函数的wait functionallity.我的意思是,是一个将mutex.lock调用队列的cpu指令,是仅在OS中实现的还是什么?
在我做的测试中,我认为这个等待函数只在OS层完成,并且创建了某种旋转,检查是否可以继续锁定,如果没有让线程进入休眠状态.是对的吗?
非常感谢你.
它取决于平台.通常,如果达到固定的旋转限制,则存在旋转锁定部分,该旋转锁定部分回退到操作系统中的阻塞.
自旋锁通常通过在互斥锁解锁时读取包含特定值的存储器地址来实现.如果它被视为未锁定,则尝试将该值从解锁值原子地更改为锁定值.如果原子交换成功,则互斥锁被锁定.通常计算旋转次数,如果达到限制,我们将切换到OS中的阻塞.
操作系统中的块通常以相同的方式实现,除了不是睡眠,线程将自己添加到等待锁定的事物列表中.当一个线程释放锁时,它会检查操作系统中是否有任何等待,如果是,则解除阻塞.这会导致操作系统安排该线程.它通常会尝试执行自旋锁尝试的相同原子交换,如果失败则再次在操作系统中阻塞.
在伪代码中:
锁定:
检查内存位置以查看锁是否已锁定.如果是,请转到步骤3.
尝试将内存位置从解锁状态原子切换为锁定状态.如果我们成功,停止,我们持有锁.
增加旋转计数.如果我们没有旋转太多次,请转到步骤1.
以原子方式增加等待此锁定的线程数.
尝试将内存位置从解锁状态原子切换为锁定状态.如果我们成功,减少等待线程的数量并停止,我们保持锁定.
有条件地阻止操作系统.
转到第5步.
解锁:
以原子方式将保持锁定状态的内存位置设置为已解锁.
如果在OS中等待此锁定的线程数大于零,请告诉操作系统取消阻止等待此锁定的所有线程.
请注意,操作系统必须实现一些机制来避免在线程设置阻塞之前发生取消阻止在OS中等待的任何线程的请求的竞争.该方法因操作系统而异.例如,Linux有一种称为"futex"的东西,它本质上是一种以原子方式实现锁定伪代码的步骤4,5和6的方法.
警告:如果您尝试在代码中实现此算法,请了解您可能会生成一个不能正常执行的玩具.您需要深入的,平台特定的知识,以避免令人讨厌的性能吸引陷阱.例如,很容易对自旋锁进行编码,以便从使用超线程共享CPU中的物理内核的另一个线程中窃取核心执行资源.并且很容易对成功的交换进行编码,以便CPU的分支预测预测它会失败并且当你获得锁定时你会采取可怕的分支错误预测惩罚.