在上一篇中我们介绍了 MPI-3 中共享内存操作,下面我们将介绍 MPI 中多线程的使用,以助于我们理解 MPI-3 中引进的线程安全的 Mprobe 操作(将在下一篇中介绍)。
进程与线程
通常 MPI 中大多数操作的基本实体是进程,但是MPI 进程中可以执行多个线程。
进程是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。通常在一个进程中可以包含若干个线程,一个进程中至少有一个线程。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程粒度更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有独立的地址空间。
MPI 多线程
MPI 进程中可以执行多个线程,同一个进程的多个线程具有均等的机会参与该进程的 MPI 通信。
某些情况下在 MPI 中使用多线程能够提供很大的方便,如:
多线程能够自然地实现非阻塞通信操作。比如可以创建一个单独的线程来执行阻塞接收操作,只要操作只阻塞该线程而不阻塞整个进程的执行,其效果就是一个非阻塞的接收操作。
线程非常适合对称多处理机(symmetric multi-processing, SMP)共享内存编程模型。
多线程能够提高某些高延时系统的性能。
在单线程的情况下,一个进程无法安全地执行到其自身的阻塞点到点通信。采用多线程,则可使同一个进程的两个线程分别执行阻塞发送和阻塞接收而不至于死锁。
MPI 要求 MPI_Init 和 MPI_Finalize 调用必须在相同线程内配对执行,执行了这两个操作的线程被称作主线程(main thread),主线程的 MPI_Finalize 调用必须在所有其它线程都执行完 MPI 相关的通信、I/O 和其它 MPI 操作之后执行。
线程安全性
线程安全性是指多个线程可以同时执行消息传递的相关调用而不会相互影响。
MPI被设计为线程安全的,但应用程序自身负责维护多线程安全,一个简单的办法是在不同线程使用不同的通信子对象,这样可实现线程间操作的互不干扰。MPI 的大多数操作都满足线程安全性的条件,但是也有例外,如在多线程中使用 MPI.Comm.Probe 或 MPI.Comm.Iprobe 来确定一个消息的来源和大小,然后接收该消息的操作就不是线程安全的,不过 MPI-3 提供了线程安全的版本 MPI.Comm.Mprobe 和 MPI.Comm.Improbe,这些将在下一篇中介绍。另外 MP