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

2021-05-03 11:47:14 +08:00
 zhongpingjing
两个线程互相竞争,A 线程获取锁执行,B 线程通过自旋来获取锁。
cpu 只有一个核心,A 线程占用了 CPU,B 应该不能自旋了吧??是不是只能等 A 执行完毕
6288 次点击
所在节点    Java
72 条回复
viakiba
2021-05-03 11:49:00 +08:00
我记得 linux 是分时调度
iseki
2021-05-03 11:52:04 +08:00
单核心时不能使用自旋锁
ch2
2021-05-03 11:55:40 +08:00
单核心不需要加锁
opengps
2021-05-03 12:02:27 +08:00
虽然有锁避免了多线程争用,但是对于单核来讲,多线程只能是轮流上岗运行的,这时候的任何线程都是要互相等待的,这也是为什么很多小众的云厂商直接从 2 核起步销售的原因,因为单核上做的工单支持过多了,单核不适合硬烧 cpu 的线上业务
nlzy
2021-05-03 12:46:20 +08:00
。。。。。。这些都是计算机操作系统课程里的基本知识了

即使计算机只有一个 CPU 核心,操作系统也可以为进程提供同时运行的假象,这叫并发。背后的原理楼上提了,就是分时调度。

题外话:在编写并发程序的时候,即使 CPU 只有一个核心,也必须要施同步(如加锁)。
vk42
2021-05-03 13:40:43 +08:00
如楼上所说单核中 spinlock 是没有意义的,具体以 Linux 来说单核情况下 spinlock 相当于 nop
Stain5
2021-05-03 15:54:51 +08:00
@nlzy 操作系统里的并发是对于不同进程间的吧,但这一过程对于单核系统的线程并没有起到并发的作用
raysonx
2021-05-03 16:31:00 +08:00
楼上好多误导楼主的。即使只有一个核,多个线程的情况下也是要加锁的,因为你无法控制操作系统进行线程调度的时机。比如在对一个变量的读和写之间切换到了另一线程就会发生 race condition 。
Jooooooooo
2021-05-03 16:58:31 +08:00
说到硬件的话就复杂了

现在很多硬件一个核也可以并行两个线程的, 不上下文切换, 共享计算单元等等
opengps
2021-05-03 17:23:15 +08:00
@Jooooooooo 借问一下,CPU 下由于存在逻辑 cpu,我能大概理解并行的意思。vCPU 下也是你说的这样不用上下文切换不?
Jooooooooo
2021-05-03 17:35:20 +08:00
@opengps 搜一下 simultaneous multi threading
uselessVisitor
2021-05-03 18:46:42 +08:00
楼主想说的是单核不能做多线程吗?可以吧。。都能新建多线程,不能用吗。。
ivechan
2021-05-03 22:14:09 +08:00
>cpu 只有一个核心,A 线程占用了 CPU,B 应该不能自旋了吧??
是的,A 线程占用了 CPU,B 线程的代码无法执行

>是不是只能等 A 执行完毕
不是的。即使 A 线程占用了 CPU,那也不意味着你能一直占着直到你的任务结束。
有因素会打算 A,然后切换到 B 。比如分给 A 任务的时间消耗完了,A 被调度出去;
比如中断和抢占打断了。


另外,不要用户态使用自旋锁,非常非常地愚蠢,除非你真的清楚自己在做什么。
引用 Linus 的话:
>I repeat: do not use spinlocks in user space, unless you actually know what you're doing. And be aware that the likelihood that you know what you are doing is basically nil.
fengjianxinghun
2021-05-03 22:24:02 +08:00
@ivechan

Linus 也不是神,大伙都在用户态 spinlock

h_t_tps://github.com/facebook/folly/blob/master/folly/synchronization/MicroSpinLock.h
vk42
2021-05-03 22:44:36 +08:00
@raysonx 没人说多线程不需要锁,lz 问的是自旋锁好吧……只有单个执行核心的情况下多线程直接用阻塞锁,用自旋锁只会浪费时间,而如果是在内核关中断的情况下甚至会有死锁。
emSaVya
2021-05-03 23:02:11 +08:00
@nlzy@raysonx 问的是 spinlock 答的什么东西 单核多线程 spinlock 无意义 遇到锁优化的 case 也不会执行自旋
raaaaaar
2021-05-04 00:25:38 +08:00
自旋锁用在频繁上下文切换比自选的开销大时使用比较多,比如信号量对里面的计数器的操作就用的自选锁,一般内核态比较多,用户态用自选锁太愚蠢了,话说所谓自选锁,你直接实现就是开个循环一直轮询,没干啥事还一直占用时间片,开销也太大了。所以一般都是用睡眠唤醒来代替的。

至于锁和核心的问题,锁主要用在进线程的同步互斥直接,和核心的关系不是很大,由于线程可以再用户态或者核心态实现,如果在用户态实现,哪怕是单核心的 u,照样宏观上使用自选锁啥的也没有问题。因为线程间抢占的是资源,是资源的竞争而不是 cpu 时间片。比如说,线程 a 在使用 s 资源,这时线程 b 也请求 s 资源,假设是单核心,现在 u 分给了 a,a 使用一段时间,但是时间片到了轮给 b,不过 a 还没有释放 s 资源,到 b 后由于请求的资源 s 没有被释放,那么 b 就一直轮询,也就是执行循环的指令。当然由于是单核心的,s 不可能被释放,所以 b 就只能一直到时间片结束,又到 a,直到 a 释放 s 资源。可以说 b 忙等待了个寂寞。

从上面也可以看出来,为什么在用户态要少用自选锁,当然如果用的信号量或者互斥锁啥的,是睡眠等待机制,那么轮到 b 后,发现 s 资源没有被释放,所以 b 调用 block 原语,阻塞掉自己陷入睡眠态,u 又轮到 a,直到 a 释放 s 资源后调用 wake 原语唤醒 b 。
Leviathann
2021-05-04 01:31:39 +08:00
单核因为没有并行,所以不可能在自旋期间发现锁被释放?
raysonx
2021-05-04 09:00:25 +08:00
@vk42 我表达的意思是多线程单核心依然需要锁,否则程序运行可能会出错。一个程序是不是需要加锁不是由执行环境有几个核心决定的,所以楼主的问题根本不需要考虑环境因素。
raysonx
2021-05-04 09:03:02 +08:00
@emSaVya 你能不能好好说话?我表达的意思是需不需要加锁和核心数无关,扯什么单核多线程 spinlock 无意义? i/o 密集应用经常使用单核多线程的模式,照样可以用自旋锁,

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

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

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

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

© 2021 V2EX