假如 CPU 只有一个核心,使用 CAS 并发竞争的问题

2021-05-03 11:47:14 +08:00
 zhongpingjing
两个线程互相竞争,A 线程获取锁执行,B 线程通过自旋来获取锁。
cpu 只有一个核心,A 线程占用了 CPU,B 应该不能自旋了吧??是不是只能等 A 执行完毕
6313 次点击
所在节点    Java
72 条回复
raysonx
2021-05-04 09:06:47 +08:00
@Leviathann 操作系统会给多线程分配不同的时间片,一个线程的时间片用完就会被操作系统挂起调用另一个线程,切换后会发现的。
raysonx
2021-05-04 09:11:10 +08:00
楼主的问题在我理解看来,是问是不是只有一个核心的情况下就没有并发了,自旋锁是不是根本就不会自旋了。答案是否,单核心情况下多个线程会被分配不同时间片进行并发,自旋期间也可能会被切换到另一个线程再切换会来。
zmxnv123
2021-05-04 09:22:00 +08:00
楼上某人单核心不加锁是搞笑的吗

你要是平时写汇编我承认你是大佬,不然建议会大学重修操作系统
IndexOutOfBounds
2021-05-04 09:26:47 +08:00
有人占着锁(临界区不可中断不是指不能上下文切换),该自旋还是会自旋,只不过单核下自旋没有意义
LeeReamond
2021-05-04 09:37:28 +08:00
@IndexOutOfBounds 有没有意义倒可以讨论一下,我感觉应该还是有,sl 除了多核心下高效利用时间片以外,单核心中也可以避免挂起的系统调用开销啊
raaaaaar
2021-05-04 09:41:12 +08:00
@LeeReamond 一般上下文切换的开销要比忙等待的开销小很多。。只有内核态那种很短的时间下可能会用到
IndexOutOfBounds
2021-05-04 10:06:00 +08:00
@LeeReamond 持有锁的线程不运行,单核自旋在时间片内注定等不到锁,不如直接阻塞,反正时间片一到也得去歇着。可能没解释对,但是我看到一些源码貌似就是基于此结论的

loopNum = coreNum == 1 ? 1 : 64 ( ConcurrentHashMap#put#1.7#伪代码)
dalabenba
2021-05-04 10:31:48 +08:00
@raysonx race condition 的原因是 core 对同一地址的写对其他 core 不可见,需要用 cas 以及 mem barrier 来保证同步,同一个核不需要锁
raysonx
2021-05-04 10:51:23 +08:00
@dalabenba mem barrier 和这个问题无关。即使所有核都直接读写内存,也需要加锁。加锁与否与核数无关,而是保证对同一地址的 Read- Modify- write 期间不会被另一个线程改写。单核情况下不加锁照样 race condition
iseki
2021-05-04 10:52:37 +08:00
单核心不能用自旋锁,另外 linus 建议不要在用户态瞎搞自旋锁,似乎是会影响调度器的判断,对吞吐量没有什么好处
dalabenba
2021-05-04 11:01:30 +08:00
@raysonx 是我想错了,确实要加锁
raysonx
2021-05-04 11:01:32 +08:00
我已经懒得去重复多线程单核心需要锁这一观点了。即使自旋锁在这种情况下效率低,也不能说可以去掉锁。不信的自己开个单核虚拟机写个程序跑跑就知道了。
OSDI
2021-05-04 11:22:18 +08:00
@raysonx lock free 呢,单核单线程自旋锁感觉就是没啥用啊,反正都得上下文切换
raysonx
2021-05-04 11:24:51 +08:00
@OSDI 我觉得楼主并不是要讨论自旋锁在单核环境下好不好的问题,讨论这个问题就偏题了。
GeruzoniAnsasu
2021-05-04 13:52:31 +08:00
@raysonx 反复看了十几遍这楼咋觉得你才是理解偏了的。。

你说得没错但确实
单核多线程自旋锁无意义


lz 想问的不就是单核多线程时调度到 A 线程,B 线程的自旋还在不在旋吗,不旋,B 线程根本就不执行,这都没啥疑问吧

原问“是不是只能等 A 执行完毕” 有歧义所以引发了争论,厘清一下:
1. 确实必须得等 A 的时间片执行完毕
2. 不必等 A 线程执行完毕






补充一下,单核多线程这种并发条件下,B 线程根本没法通过自己去“抢占”资源,如果 A 没有释放锁,B 拿到的时间片会全部浪费在自旋上,还不如直接等待
GuuJiang
2021-05-04 14:07:55 +08:00
这篇帖子生动地展示了什么叫作“你在第二层,你以为我在第一层,实际我在第五层”
按照“是不是只能等 A 执行完毕”这样的表述,提问者应该在第一层,估计还没有形成时间片这个概念,于是第二层的人敏锐地意识到了这一点,指出了不管是不是单核,实际都有并发,但是这个帖子好巧不巧提到了自旋,于是引来了第五层的人,指出了在单核环境下自旋是无意义的,但是第二层的人无法区分第一层和第五层,把所有第五层的对手都当第一层的来辩论
ipwx
2021-05-04 14:55:53 +08:00
不要使用自旋——但是有些场景例外。比如你要争取在一个消息队列系统里面消除 20us 的调度延迟(如果用 mutex 等待大概就是这个量级)
namelosw
2021-05-04 18:53:39 +08:00
菜鸡有个问题想问第五层的大佬:

单核自旋没意义,这个结论是否适用于单核有超线程 (HT 不是多线程) 的情况?
raysonx
2021-05-04 19:17:29 +08:00
@GuuJiang 单核环境下自旋当然不是无意义的,起到加锁的作用就是它的意义,只是比较浪费 CPU 计算资源而已,去掉锁会出错。讨论单核下自旋锁是不是一个比较优的方案偏离本题。
IndexOutOfBounds
2021-05-04 19:20:11 +08:00
@namelosw
单核超线程,只是充分利用上下文切换的时间而已。
不能并行,自旋就没有意义

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/774722

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX