多个内核/处理器上的多线程

时间:2019-10-30 21:47:23

标签: multithreading mutex

我的想法是,如果锁定和解锁互斥锁是原子操作,那么在单处理器体系结构的情况下,它可以保护代码的关键部分。 任何将首先进行调度的线程都将能够在单个机器代码操作中“锁定”互斥锁。 但是,当线程在多个内核上运行时,互斥锁有什么好处? (其中不同的线程可以同时在不同的“核心”上同时运行)。 我似乎无法掌握多线程程序如何在多个内核上没有任何死锁或竞争条件的情况下工作的想法?

3 个答案:

答案 0 :(得分:1)

线程是由操作系统管理的,操作系统负责将线程调度到内核,因此也可以避免将特定线程调度到内核上。

互斥锁是操作系统的概念。您基本上是在要求操作系统阻塞一个线程,直到其他线程告诉操作系统可以了

答案 1 :(得分:0)

在现代操作系统上,线程是物理硬件的抽象。程序员将线程作为代码执行的抽象。没有可用的硬件核心的单独抽象。操作系统负责将线程映射到物理内核。

互斥锁是驻留在系统内存中的数据结构。任何具有访问权限的线程都可以读取该内存位置,而不管它运行在哪个线程或内核上。无论您的代码是在内核1还是20上执行都无所谓,它仍然可以读取内存的当前状态。锁定。

换句话说,无论线程或内核有多少,都只有共享的系统内存可供它们执行操作。

答案 2 :(得分:0)

一般答案:

Mutexes是一个操作系统概念。提供互斥锁的操作系统必须确保这些互斥锁在该操作系统要支持的所有硬件上正常工作。如果特定硬件无法实现互斥锁,则操作系统无法在该硬件上提供互斥锁。如果操作系统要求存在互斥才能正常工作,则它根本无法支持该硬件。毫无疑问,操作系统如何为特定硬件实现互斥锁是非常依赖硬件的,并且在操作系统及其支持的硬件之间有很大的差异。


详细答案:

大多数通用CPU提供原子操作。这些操作被设计为在系统中的所有CPU内核上都是原子的,无论这些内核是单个CPU还是多个CPU的一部分。

仅需两个原子操作atomic_oratomic_and,就可以实现锁定。例如。想起

int atomic_or ( int * addr, int val )

它原子地计算*addr = *addr | val并在执行计算之前返回*addr的旧值。如果*lock == 0和多个线程调用atomic_or(lock, 1),则只有其中一个将得到0作为结果;只有第一个执行该操作的线程。所有其他线程的结果为1。拥有0的一个线程是获胜者,它拥有锁,所有其他线程都注册一个事件并进入睡眠状态。

优胜者线程现在具有对atomic_or之后部分的独占访问权,它可以执行所需的工作,完成后,它只需再次清除锁定(atomic_and(lock, 0))并生成系统事件,该锁现在又可以使用了。

然后,系统将在进入睡眠状态之前唤醒为此事件注册的一个,一些或所有线程,并且争夺锁的过程将重新开始。唤醒线程中的一个会赢得比赛,也可能不会赢得比赛,因为另一个线程甚至更快,并且可能在atomic_and和其他线程还未唤醒之前就已经抓住了锁,但这没关系并且仍然正确,因为它仍然只有一个线程可以访问。所有未能获得锁的线程都将重新进入睡眠状态。

当然,现代系统的实际实现通常要复杂得多,它们可能会考虑诸如线程优先级之类的事情(在锁定竞争中可能会首选高优先级的prio线程),或者可能确保每个线程都在等待互斥锁最终也会得到它(存在一些预防措施,可以防止线程始终丢失锁竞争)。另外,互斥锁可以是递归的,在这种情况下,系统确保同一线程可以多次获得相同的互斥锁而不会出现死锁,这需要额外的簿记。

也许不必多说,但是原子操作是更昂贵的操作,因为它们需要系统内的内核同步其工作,这会减慢其处理吞吐量。如果所有内核都在单个CPU上运行,它们可能会有些昂贵,但是如果有多个CPU,它们甚至可能会非常昂贵,因为同步必须在将CPU彼此连接的CPU总线系统上进行,而该总线系统通常不会以CPU速度运行。

另一方面,使用互斥锁始终会降低处理速度,因为如果多个线程同时需要访问才能继续工作,则提供对资源的独占访问必须减慢处理速度。因此,对于实现互斥锁是无关紧要的。实际上,尽管您可以仅使用原子操作而不使用功能齐全的互斥锁以线程安全的方式实现功能,但是尽管这些操作比普通操作更昂贵,但是您通常会获得明显的速度优势。