我知道在单核处理器中使用信号量可以轻松完成同步。但是,如果我们有多核,如果多个进程想要在相同的时刻进入关键部分,那么它们是否都进入了关键部分或只有一个获胜?获胜者进程赢得了什么标准?
答案 0 :(得分:1)
当两个内核同时尝试进入临界区时,它们都尝试使用锁定的读 - 修改 - 写操作同时写入内存中的信号量。为了使内核完成写入,高速缓存必须获得对包含信号量的高速缓存行的独占访问权。这会强制另一个核心将该行标记为无效。缓存协议确保只有一个核心可以获得独占访问权限,并且该核心进入关键部分。
与此同时,另一个也在尝试写入信号量的核心必须等待,因为它仍然需要对缓存行进行独占访问。一旦第一个核完成其写操作,另一个核就会获得独占访问权并可以完成其读 - 修改 - 写。但是read-modify-write的结果告诉它信号量很忙,所以在检测到信号量已经释放之前它不能进入临界区。
答案 1 :(得分:1)
即使存在多个核心,信号量(或互斥量或大多数其他同步原语)的工作方式也相同 - 只有指定数量的线程才能进入信号量。如果它只在单处理器机器上工作,那将是一个糟糕的信号量!
完成这项工作需要多种机制,我会尝试提供高级视图。
请注意,内存仍在不同内核之间共享。理解如何使用共享内存同步核心的简化但IMO有用的方法是CMPXCHG
instruction。该指令可以原子地(参见下面的更多细节)比较并设置存储器地址。如果内存地址具有您要比较的值,它还会将零标志设置为1。
请考虑以下代码:
wait:
mov eax, 0
mov ecx, 1
lock cmpxchg [address of lock], ecx
jne wait
// We now own the lock
代码在逻辑上循环执行以下操作:仅当lock
为0时才将lock
的值设置为1.
此代码可由多个核心运行,cmpxchg
的原子性保证只有一个核心将获胜。
如果每个核心都有自己的缓存(现在通常就是这种情况),情况会变得更复杂。对于单独的缓存,每个核心都有自己的内存视图,因此必须注意确保这些内存视图是一致的。简短的回答是,这可以通过让缓存在数据更改时相互通知来完成,这样其他缓存可以在需要时使其副本无效或更新。查看窥探和MESI协议以获取更多详细信息。
请注意,如果内核位于同一个物理芯片上,那么它们都会竞争内存总线,并且存在在内核之间共享它的机制(例如仲裁机制;也可以查找LOCK
指令)。
答案 2 :(得分:0)
信号量只是在一个系统中对线程进行信号化的方法之一。您可以在一个或多核CPU中使用信号量,这对他的使用没有影响。
现在回到你的问题。如果您有关键部分,并且多个线程想要进入该区域,那么它们将在该区域中全部运行。您需要了解主线程(例如)或其他将启动它们的线程,它们之间会产生一些时间间隔(非常小的时间空间在几个ns附近)。 这就是我们使用信号化的原因,因为我们不想要“赢家”,而在其他方面,几乎在所有情况下,线程都可以在该关键部分进行不必要的更改。
在单核系统中,您只能实现一个并发的进程调度(假的并行性,通过TaskScheduler),因为不同的阶段必须通过分配的时隙共享核心。