自旋锁(spinlock)很好理解。对自旋锁加锁的操作,你可以认为是类似这样的:
while (抢锁(lock) == 没抢到) { }
只要没有锁上,就不断重试。显然,如果别的线程长期持有该锁,那么你这个线程就一直在 while while while 地检查是否能够加锁,浪费 CPU 做无用功。
仔细想想,其实没有必要一直去尝试加锁,因为只要锁的持有状态没有改变,加锁操作就肯定是失败的。所以,抢锁失败后只要锁的持有状态一直没有改变,那就让出 CPU 给别的线程先执行好了。这就是互斥器(mutex)也就是题目里的互斥锁(不过个人觉得既然英语里本来就不带 lock,就不要称作锁了吧)。对互斥器加锁的操作你可以认为是类似这样的:
while (抢锁(lock) == 没抢到) { 本线程先去睡了请在这把锁的状态发生改变时再唤醒(lock); }
操作系统负责线程调度,为了实现「锁的状态发生改变时再唤醒」就需要把锁也交给操作系统管理。所以互斥器的加锁操作通常都需要涉及到上下文切换,操作花销也就会比自旋锁要大。
以上两者的作用是加锁互斥,保证能够排它地访问被锁保护的资源。
不过并不是所有场景下我们都希望能够独占某个资源,很快你可能就会不得不写出这样的代码:
// 这是「生产者消费者问题」中的消费者的部分逻辑 // 等待队列非空,再从队列中取走元素进行处理 加锁(lock); // lock 保护对 queue 的操作 while (queue.isEmpty()) { // 队列为空时等待 解锁(lock); // 这里让出锁,让生产者有机会往 queue 里安放数据 加锁(lock); } data = queue.pop(); // 至此肯定非空,所以能对资源进行操作 解锁(lock); 消费(data); // 在临界区外做其它处理
你看那个 while,这不就是自己又搞了一个自旋锁么?区别在于这次你不是在 while 一个抽象资源是否可用,而是在 while 某个被锁保护的具体的条件是否达成。
有了前面自旋锁、互斥器的经验就不难想到:「只要条件没有发生改变,while 里就没有必要再去加锁、判断、条件不成立、解锁,完全可以让出 CPU 给别的线程」。不过由于「条件是否达成」属于业务逻辑,操作系统没法管理,需要让能够作出这一改变的代码来手动「通知」,比如上面的例子里就需要在生产者往 queue 里 push 后「通知」!queue.isEmpty() 成立。
也就是说,我们希望把上面例子中的 while 循环变成这样:
while (queue.isEmpty()) { 解锁后等待通知唤醒再加锁(用来收发通知的东西, lock); }
生产者只需在往 queue 中 push 数据后这样,就可以完成协作:
触发通知(用来收发通知的东西); // 一般有两种方式: // 通知所有在等待的(notifyAll / broadcast) // 通知一个在等待的(notifyOne / signal)
这就是条件变量(condition variable),也就是问题里的条件锁。它解决的问题不是「互斥」,而是「等待」。
至于读写锁(readers-writer lock),看英文可以顾名思义,在执行加锁操作时需要额外表明读写意图,复数读者之间并不互斥,而写者则要求与任何人互斥。读写锁不需要特殊支持就可以直接用之前提到的几个东西实现,比如可以直接用两个 spinlock 或者两个 mutex 实现:
void 以读者身份加锁(rwlock) { 加锁(rwlock.保护当前读者数量的锁); rwlock.当前读者数量 += 1; if (rwlock.当前读者数量 == 1) { 加锁(rwlock.保护写操作的锁); } 解锁(rwlock.保护当前读者数量的锁); } void 以读者身份解锁(rwlock) { 加锁(rwlock.保护当前读者数量的锁); rwlock.当前读者数量 -= 1; if (rwlock.当前读者数量 == 0) { 解锁(rwlock.保护写操作的锁); } 解锁(rwlock.保护当前读者数量的锁); } void 以写者身份加锁(rwlock) { 加锁(rwlock.保护写操作的锁); } void 以写者身份解锁(rwlock) { 解锁(rwlock.保护写操作的锁); }
如果整个场景中只有一个读者、一个写者,那么其实可以等价于直接使用互斥器。不过由于读写锁需要额外记录读者数量,花销要大一点。
你可以认为读写锁是针对某种特定情景的「优化」。但个人还是建议忘掉读写锁,直接用互斥器。
感谢
@sxc邀请。非常非常感谢。
为了防止邀请我的sxc老师撤销邀请,我不得不截图。
@朱峰女士,你的答案,为了防止你进行修改,我已经截图了。没错,如你问题当中所说,礼貌是不是软弱?
当然不是。
我自问是一个普通人,在知乎得到关注多,也只是因为我勤勤恳恳,一个字一个字写得多,仅此而已。
我去咕咚网之前,当过记者,做过公关,我也不是什么名校毕业,但是我深深知道,原创是品德,是节操。做记者,报道要如实,要客观,要中立,要还原事情的本来面目。
我为什么要在微信群“红包体育”里面和你抬杠,为什么要质问你,想必你已经不记得了,然而我记得清清楚楚。
我不关注你的微信号,那是有非常重要的原因的。朱峰女士,你说你没做过亏心事,那么想必在你看来,未经他人许可引用、转载他人原创的内容,不算是亏心事了。
你不记得的事情,我一点一点帮你回忆起来吧。事情当然没有这么简单。
当你加入“红包体育”的时候,我对群主说了一句话。【我很高兴,我有不删除任何聊天软件当中聊天记录的好习惯。】
这里截图当中的日期是一直就存在的。至今我的iPhone 4S也一直在用呢,不可能改掉。
你为什么和我说抱歉,你忘了?2015年3月3日你所说的,是真的都不记得了?
当时我的反应,算是很克制的了,毕竟当着“红包体育”群里这么多人的面。
为什么我过了这么久,才再次在“红包体育”群里质问你,我想你应该明白。我知道每个人做自媒体不容易,想靠着才华变现,更加不容易,当时你肯道歉,说你会改,那么我也就得过且过了。
问题的关键在于,你改了吗?如果你改了,你就不会不经过
@式微同意,转载她的答案,而且还将她列为“第二作者”。
你的所谓声明,夹杂在你的正文内容当中,而不是正式开辟一个子栏目道歉,被诸多的信息噪声遮盖着,这就是你的诚意?
上述三张截图,是2015年6月17日早上8:43时截的。我现在还很怕诸多水军说我图片造假呢。下面两张图,是2015年3月3日晚上20:49时截的。那个时候,你的微信ID还没有“太阳表情”。
这个总不能说我作假了吧?
而你在面对我的质疑的时候,说了些什么话,你还记得吗?这就是我为什么要截图的原因。
二次编辑加了些东西,就可以等同于你自己的原创,是吗?
事实证明我当初心一软得过且过,才是真的错误。
你说了“最初开时,格式内容混乱,但转载内容标明了作者”——我还是那句话:用了我的东西,问过我吗?
你说了“微信对于转载格式有了新要求后,我们也跟着学习,把之前来源不明的全部删除。之后再也没有出现不合规的转载“——来源不明?请看看截图,你自己说过的话,怎么就这么快忘了呢?”是从虎扑、知乎、直播吧很多来源的文章“,这还算是来源不明?
你说了“暴力行为冠以道德名义,缺又恰恰选择了一个认真做事的自媒体下手,无论是出于要稿费,还是炒作涨粉,都不会实现的”——暴力冠以道德的名义?我质问你,就是暴力,你不告而拿,拿了我的答案,也拿了知乎上别人的答案,这种偷窃行为,就是道德的?
另外,请弄清楚,到底谁在炒作?我只是把原文作者式微老师带到了“体育红包”群,让她自己和你说清楚,这就是炒作?式微维护自己正当权益没有成功,自己写了篇专栏,以正视听,这叫炒作?
你说了“另外。。。您在背后诽谤我的许多聊天截图我已经给了律师。我们没做亏心事,我们礼貌但不软弱,真的,用法律途径解决,只对我们单方面有利啊。但您若真的要这样苦苦相逼,请也不吝给我一个您的地址,给您去一封律师函”。
我在背后诽谤你?请把截图放出来,让知乎用户都看看,我到底怎么诽谤你了。
你没做亏心事?没做亏心事我会质问你为什么不经过我允许转载了我的内容?
说我苦苦相逼?到底谁逼谁?“咕咚-李旸”是我在“红包体育”群里的ID,那是因为之前说过要标清楚所在的企业、媒体和姓名,所以我这样写。
我再说一次:质问你,是因为你在知乎未经我许可,擅自转载和引用了我的内容;我质问你,是因为你在知乎未经式微老师的许可,擅自转载和引用了式微老师的内容。
知乎上的回答问题,是我业余时间所为,工作忙的时候我只能下班回答问题,晚上写公众号内容,或者把知乎的答案放到我自己的公众号上去。关于足球篮球的内容,和咕咚网没有一点关系,全部是我自己的业余创作。
而你,直接找到了咕咚创始人、CEO申波先生,也就是我的最高领导,去质问我的行为是代表咕咚,还是代表个人。
我在知乎的ID和个人说明写得清清楚楚,没有和咕咚有任何的关联。你没有经过我个人的允许,转载引用我在知乎的内容,被我质疑你转载了别人的内容,居然好意思说是“法律层面的诽谤”?居然还去和我供职的企业对质?
到底是谁苦苦相逼?
所谓认真做事的自媒体,是把知乎用户的文字答案,变成自己的声音和话语,放到视频当中去,是吗?
所谓认真做事的自媒体,是未经他人许可,擅自转载、引用他人在知乎的原创答案,是吗?
最后我很想问一句:你既然深知自媒体人的成长有多么不易,为什么你还要去做“未经许可,擅自转载和引用其他自媒体人的内容”这样的事情?
最后,是我放出的所有截图的具体信息。
我在这里声明:我是知乎用户李暘,在知乎的每一个答案,在知乎的每一篇专栏文章,不敢保证完美无缺,逻辑严密,没有错别字,但全部是我自己的原创内容,任何人未经我许可,转载、引用、抄袭我的答案,即为侵权行为。