MPI-Avoid deadlock
2015-08-22 00:02
253 查看
MPI-DEADLOCK ISSUE!
设进程i向i+1发送数据(循环进行,周期性拓扑)。进行i可以用标准模式向右边近邻发送数据,然后用blocking模式接收左边近邻的数据。
对每一个进程而言,接收操作在发送操作没有完成之前不能执行。但发送操作是否完成,和接收操作有关,因此,上面的代码有循环依赖问题。由于使用标准模式的发送,send操作可能block,直到有一个匹配的接收操作出现。
以上代码只有在系统有充分大的buffer的时候才能工作,此时,send操作由于数据被拷贝的buffer中因此能返回,因此,匹配的receive操作能够执行。如果没有足够的buffer,MPI未指定输出,但对很多MPI的实现来说,将造成deadlock. 即MPI_Send永远不会返回,每一个进程都在等待下一个进程执行相应的receive操作。因此上面的代码在不同系统上有不同的行为,在同一个系统上,依据消息的尺寸,行为也会不同。
有以下几个方法来避免以上问题:
第一:在不同进程上,颠倒send和receive的次序(至少两个进程才能正确工作)
设有3个进程,首先0号准备接收来自2号的消息,2号准备接收来自1号的消息,而1号首先发送消息给2号,2号已经准备接收,所以1号的发送能够正确返回,然后2号的接收能正确返回,然后2号发送到0号执行,0号接收能够正确执行,然后0号发送1号开始,1号现在能够接收,正确返回。因此上述代码消除了deadlock.
第二个方法是利用non-blocking 通讯。可以使用non-blocking 的send或receive或者两个都用non-blocking模式。其区别在于,如果一个使用non-blocking的send,MPI_Isend能够开始一个send操作并且立即返回,然后后面的receive能够执行,从而使得整个通讯过程能够顺利完成。应注意的是,在调用MPI_Isend之后,在buf1中的data不能被立即修改,直到确保数据已经被发送或拷贝到系统缓存之中。MPI 提供MPI_Wait和MPI_Test来检查这些状态:
还可以先执行non-blocking的receive:
MPI_Irecv将首先post一个receive,然后执行后面的blocking send操作。MPI_Irecv暗示MPI收到的数据应该存在buf2中,MPI_Wait用来阻塞程序,直到输入数据实质上被接收进了buf2.这个模式通常导致更快的速度,因为在很多MPI实现上,当一个匹配的receive已经被post的时候,send操作完成的特别快(不需要握手信号)。
当然,也可以用MPI_Sendrecv解决问题:
设进程i向i+1发送数据(循环进行,周期性拓扑)。进行i可以用标准模式向右边近邻发送数据,然后用blocking模式接收左边近邻的数据。
MPI_Comm_size(comm,&size); MPI_Comm_rank(comm,&rank); rightrank = (rank+1)%size; leftrank = (rank+size-1)%size; MPI_Send(buf1,count,MPI_INT,rightrank,tag,comm); MPI_Recv(buf2,count,MPI_INT,leftrank,tag,comm,&status);
对每一个进程而言,接收操作在发送操作没有完成之前不能执行。但发送操作是否完成,和接收操作有关,因此,上面的代码有循环依赖问题。由于使用标准模式的发送,send操作可能block,直到有一个匹配的接收操作出现。
以上代码只有在系统有充分大的buffer的时候才能工作,此时,send操作由于数据被拷贝的buffer中因此能返回,因此,匹配的receive操作能够执行。如果没有足够的buffer,MPI未指定输出,但对很多MPI的实现来说,将造成deadlock. 即MPI_Send永远不会返回,每一个进程都在等待下一个进程执行相应的receive操作。因此上面的代码在不同系统上有不同的行为,在同一个系统上,依据消息的尺寸,行为也会不同。
有以下几个方法来避免以上问题:
第一:在不同进程上,颠倒send和receive的次序(至少两个进程才能正确工作)
if(rank%2){ MPI_Recv(buf2,count,MPI_INT,leftrank,tag,comm,&status); MPI_Send(buf1,count,MPI_INT,rightrank,tag,comm); else{ MPI_Send(buf1,count,MPI_INT,rightrank,tag,comm); MPI_Recv(buf2,count,MPI_INT,leftrank,tag,comm);
设有3个进程,首先0号准备接收来自2号的消息,2号准备接收来自1号的消息,而1号首先发送消息给2号,2号已经准备接收,所以1号的发送能够正确返回,然后2号的接收能正确返回,然后2号发送到0号执行,0号接收能够正确执行,然后0号发送1号开始,1号现在能够接收,正确返回。因此上述代码消除了deadlock.
第二个方法是利用non-blocking 通讯。可以使用non-blocking 的send或receive或者两个都用non-blocking模式。其区别在于,如果一个使用non-blocking的send,MPI_Isend能够开始一个send操作并且立即返回,然后后面的receive能够执行,从而使得整个通讯过程能够顺利完成。应注意的是,在调用MPI_Isend之后,在buf1中的data不能被立即修改,直到确保数据已经被发送或拷贝到系统缓存之中。MPI 提供MPI_Wait和MPI_Test来检查这些状态:
MPI_Isend(buf1,count,MPI_INT,rightrank,tag,comm,&request); MPI_Recv(buf2,count,MPI_INT,leftrank,tag,comm,&status); MPI_Wait(&request,&status);
还可以先执行non-blocking的receive:
MPI_Irecv(buf2,count,MPI_INT,leftrank,tag,comm,&request); MPI_send(buf1,count,MPI_INT,rightrank,tag,comm); MPI_Wait(&request,&status);
MPI_Irecv将首先post一个receive,然后执行后面的blocking send操作。MPI_Irecv暗示MPI收到的数据应该存在buf2中,MPI_Wait用来阻塞程序,直到输入数据实质上被接收进了buf2.这个模式通常导致更快的速度,因为在很多MPI实现上,当一个匹配的receive已经被post的时候,send操作完成的特别快(不需要握手信号)。
当然,也可以用MPI_Sendrecv解决问题:
MPI_Sendrecv(buf1,count,MPI_INT,rightrank,tag, buf2,count,MPI_INT,leftrank,tag,comm,&status);
相关文章推荐
- Linux C函数参考手册(PDF版)
- Oracle外键不加索引引起死锁示例
- Lua教程(十七):C API简介
- SQL2008中SQL应用之- 死锁(Deadlocking)
- C#中lock死锁实例教程
- C#实现打造气泡屏幕保护效果
- C/C++数据对齐详细解析
- 利用C语言来求最大连续子序列乘积的方法
- 字符串的组合算法问题的C语言实现攻略
- C 语言基础教程(我的C之旅开始了)[三]
- C++中的extern “C”用法详解
- C 语言基础教程(我的C之旅开始了)[七]
- 最大子矩阵问题实例解析
- C字符串操作函数实现方法小结
- 字典树的基本知识及使用C语言的相关实现
- 利用sys.sysprocesses检查SqlServer的阻塞和死锁
- C/C++ 宏详细解析
- 使用C语言解决字符串全排列问题
- C/C++实现对STORM运行信息查看及控制的方法