ste*_*fan 20 c++ multithreading mpi thread-safety c++11
根据这个网站,使用MPI::COMM_WORLD.Send(...)是线程安全的.但是在我的应用程序中,我经常(并非总是)遇到死锁或出现分段错误.MPI::COMM_WORLD使用a 封闭每个方法调用mutex.lock()并mutex.unlock()始终如一地删除死锁以及段错误.
这是我创建线程的方式:
const auto communicator = std::make_shared<Communicator>();
std::vector<std::future<size_t>> handles;
for ( size_t i = 0; i < n; ++i )
{
handles.push_back(std::async(std::launch::async, foo, communicator));
}
for ( size_t i = 0; i < n; ++i )
{
handles[i].get();
}
Run Code Online (Sandbox Code Playgroud)
Communicator是一个有std::mutex成员的类,专门调用诸如MPI::COMM_WORLD.Send()和之类的方法MPI::COMM_WORLD.Recv().我没有使用任何其他方法发送/接收MPI.foo采取一个const std::shared_ptr<Commmunicator> &论点.
我的问题:MPI承诺的线程安全性与创建的线程不兼容std::async吗?
Hri*_*iev 28
MPI中的线程安全无法开箱即用.首先,您必须确保您的实现实际上支持多个线程立即进行MPI调用.对于一些MPI实现,例如Open MPI,这需要在构建时为库配置特殊选项.然后你必须告诉MPI在适当的线程支持级别初始化.目前,MPI标准定义了四个级别的线程支持:
MPI_THREAD_SINGLE - 表示用户代码是单线程的.这MPI_Init()是使用时初始化MPI的默认级别;MPI_THREAD_FUNNELED - 表示用户代码是多线程的,但只有主线程才能进行MPI调用.主线程是初始化MPI库的线程;MPI_THREAD_SERIALIZED - 表示用户代码是多线程的,但是对MPI库的调用是序列化的;MPI_THREAD_MULTIPLE - 表示用户代码是多线程的,并且所有线程都可以随时进行MPI调用而无需任何同步.为了使用线程支持初始化MPI,必须使用MPI_Init_thread()而不是MPI_Init():
int provided;
MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
if (provided < MPI_THREAD_MULTIPLE)
{
printf("ERROR: The MPI library does not have full thread support\n");
MPI_Abort(MPI_COMM_WORLD, 1);
}
Run Code Online (Sandbox Code Playgroud)
与已过时(并从MPI-3中删除)C++绑定的等效代码:
int provided = MPI::Init_thread(argc, argv, MPI::THREAD_MULTIPLE);
if (provided < MPI::THREAD_MULTIPLE)
{
printf("ERROR: The MPI library does not have full thread support\n");
MPI::COMM_WORLD.Abort(1);
}
Run Code Online (Sandbox Code Playgroud)
线程的支持水平进行排序是这样的:MPI_THREAD_SINGLE< MPI_THREAD_FUNNELED< MPI_THREAD_SERIALIZED< MPI_THREAD_MULTIPLE,所以任何其他规定的水平,从不同MPI_THREAD_MULTIPLE会有数值更低-这就是为什么if (...)上面的代码是这么写的.
MPI_Init(&argc, &argv)相当于MPI_Init_thread(&argc, &argv, MPI_THREAD_SINGLE, &provided).实现不需要在请求的级别完全初始化 - 而是可以在任何其他级别(更高或更低)初始化,这在provided输出参数中返回.
有关更多信息,请参阅MPI标准的第12.4节,此处免费提供.
对于大多数MPI实现,级别的线程支持MPI_THREAD_SINGLE实际上等同于级别提供的MPI_THREAD_SERIALIZED- 正是您在案例中观察到的.
由于您没有指定您使用的MPI实现,因此这里有一个方便的列表.
我已经说过必须使用正确的标志编译Open MPI才能支持MPI_THREAD_MULTIPLE.但还有另一个问题 - 它的InfiniBand组件不是线程安全的,因此在完全线程支持级别初始化时,Open MPI不会使用本机InfiniBand通信.
英特尔的MPI有两种不同的版本 - 一种支持,一种不支持完整的多线程.通过将-mt_mpi选项传递给MPI编译器包装器来启用多线程支持,该包装器启用与MT版本的链接.如果启用了OpenMP支持或自动并行器,则也会隐含此选项.我不知道启用完整线程支持时IMPI中的InfiniBand驱动程序如何工作.
MPICH(2)不支持InfiniBand,因此它是线程安全的,可能最新版本提供MPI_THREAD_MULTIPLE开箱即用的支持.
MVAPICH是构建英特尔MPI的基础,它支持InfiniBand.在使用InfiniBand的机器上使用时,我不知道它在完全线程支持级别上的行为.
关于多线程InfiniBand支持的说明非常重要,因为现在许多计算集群都使用InfiniBand结构.随着IB组件(openibOpen MPI中的BTL)被禁用,大多数MPI实现切换到另一个协议,例如TCP/IP(tcpOpen MPI中的BTL),这导致更慢和更潜在的通信.
| 归档时间: |
|
| 查看次数: |
6053 次 |
| 最近记录: |