进程间通信包括两个主要操作:数据移动和通知(包括同步)
多核模型要求能够同步核心并在核心之间发送通知。一个典型的同步用例是当一个内核执行完所有系统初始化时,所有其他内核必须等到初始化完成后才能继续执行。并行处理中的分叉点和接合点需要核心之间(可以想象是核心的子集)的同步。同步和通知可以使用Multicore Navigator或通过CPU执行来实现。将数据从一个核心传输到另一个核心需要通知。
对于non-navigator数据传输,在发送方准备好通信消息数据,使用shared、dedicated或transitional memory交付给接收方之后,有必要通知接收方消息可用性。通过direct(直接)、indirect(间接)信号或atomic arbitration(原子仲裁)来实现。
直接信号(Direct Signaling)
这些设备支持一个简单的外围设备,允许一个核心向另一个核心生成物理事件。该事件与所有其他系统事件一起通过核心的本地中断控制器进行路由。可以选择此事件是生成CPU中断,还是CPU轮询其状态。外围设备包括一个标志寄存器,用于指示事件的发起者,以便通知的CPU可以采取适当的操作(包括清除标志),如下图所示:
处理步骤如下:
- CPU A写入CPU B的处理器间通信(IPC)控制寄存器
- 产生中断控制器的IPC事件
- 中断控制器通知CPU B(或轮询)
- CPU B查询IPC
- CPU B查询IPC标志
- CPU B执行适当的操作
间接信号(Indeirect Signaling)
如果使用第三方传输(如EDMA控制器)来移动数据,则核心之间的信号可以通过间接信号传输来执行。换句话说,通知遵循硬件中的数据移动,而不是通过软件控制,如下图所示:
处理步骤如下:
- CPU A配置并且触发EDMA传输
- 为中断控制器生成EDMA完成事件
- 中断控制器通知CPU B(或轮询)
原子仲裁(Atomic Arbitration)
每个设备都包括对原子仲裁的硬件支持。支持架构在不同的设备上有所不同,但可以轻松实现相同的底层功能。在所有设备上,CPU都可以自动获取锁,修改任何共享资源,并将锁释放回系统。
硬件保证锁本身的获取是原子的,这意味着在任何时候只有一个内核可以拥有它。硬件无法保证与锁相关的共享资源受到保护。相反,锁是一种硬件工具,它允许软件下表和下图所示的定义良好(且简单)的协议来保证原子性
在OpenMP中同步
使用OpenMP,同步可以是隐式的,也可以使用编译器指令显示定义。
线程同步在并行或工作共享构造的末尾是隐式的。这意味着,在一个组中的所有其他线程都到达代码块的末尾之前,任何线程都无法继续。
还可以显示定义同步指令。例如,临界构造确保一次只有一个线程可以进入代码块。重要的是要包含一个唯一的区域名为"#pragma omp critical<region name>"。如果关键部分未命名,线程将不会进入任何关键区域。显示同步指令的另一个示例是原子指令。原子指令和关键指令之间有一些关键区别:原子指令仅适用于一行代码,该行代码被转换为基于硬件的原子操作,因此比适用于代码块的关键构造更依赖于硬件,可移植性更低。
参考文献:
- 《Multicore Programming Guide》