MPI学习--阻塞通信之标准通信模式
本篇通过一个小例子来总结下阻塞通信中的标准通信模式
阻塞通信
阻塞通信是指消息发送发的send
调用需要接收方的recv
调用的配合才可完成。即在发送的消息信封和数据被安全的“保存”起来之前,send
函数的调用不会返回。
所谓的安全保存,就是指send
调用可再次被执行而不会对上一次发送的数据带来任何破坏。
不同模式下所要求的“配合”程度也不同,尤其有的MPI环境下还要结合运行时环境本身提供的缓存机制综合考虑实际效果。
标准通信模式
1 |
|
使用mpicc
脚本编译,执行:1
2
3
4
5
6
7
8[zjshao@master ch02]$ mpicc -std=c99 std_send_recv.c -o std_send_recv.x
[zjshao@master ch02]$ mpiexec -n 2 std_send_recv.x
process 1 of 2 sending data...
process 1 of 2 receiving data...
process 0 of 2 sending data...
process 0 of 2 receiving data...
Hello world, process 1 of 2
Hello world, process 0 of 2
从输出的可以看出,进程1的发送和接受操作要早于进程0,因此进程0发送数据时,进程1可立即进行接收,立即实施传输操作。而进程1在调用recv的时候才开始进行消息传输,之前的进程1的数据存在MPI的缓冲区中。
缓冲区
我觉得到这里可以总结下缓冲区了。
MPI环境定义了3中缓冲区:应用缓冲区、系统缓冲区、用户向系统注册的缓冲区(通信缓冲区)。
应用缓冲区
就是在程序中开辟的内存空间的地址,也就上面代码中的sb
和rb
分别代表发送数据和接收数据的缓冲区地址,本质上呢就是一个数组的首地址。
系统缓冲区
是MPI环境为通信所准备的存储空间。类似于一个数据中转站,应用缓冲区的数据在系统缓冲区中复制入和出,即发送数据的时候从系统缓冲区将数据复制到系统缓冲区,接收数据的时候从系统缓冲区复制到应用缓冲区。
用户向系统注册的缓冲区
是指用户使用某些API(如MPI_Bsend
)时,在程序中显式申请的存储空间,然后注册到MPI环境中共通讯所用。
接收和发送信息的几种情况测试
只有接收没有发送
将上面的程序进程0的发送消息的部分注释掉:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// Send and receive data in proc 0.
if (myid == 0)
{
//fprintf(stderr, "process %d of %d sending data...\n", myid, nprocs);
//MPI_Send(sb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD);
fprintf(stderr, "process %d of %d receiving data...\n", myid, nprocs);
MPI_Recv(rb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD, &status);
}
// Send and receive data in proc 1.
if (myid == 1)
{
fprintf(stderr, "process %d of %d sending data...\n", myid, nprocs);
MPI_Send(sb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD);
fprintf(stderr, "process %d of %d receiving data...\n", myid, nprocs);
MPI_Recv(rb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD, &status);
}
则输出的结果是:1
2
3
4
5
6
7
8[zjshao@master ch02]$ mpiexec -n 2 std_send_recv_2.x
process 1 of 2 sending data...
process 0 of 2 receiving data...
process 1 of 2 receiving data...
Hello world, process 0 of 2
[mpiexec@master.cluster] Sending Ctrl-C to processes as requested
[mpiexec@master.cluster] Press Ctrl-C again to force abort
[zjshao@master ch02]$
程序卡在了进程1接收来自进程0消息的地方无法返回,而进程0这个时候已经将程序执行完毕,输出了HelloWorld。最终只能向进程发送CTRL C
来终止MPI进程。
只有发动没有接收
将上面的程序进程1的接收消息的部分注释掉:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// Send and receive data in proc 0.
if (myid == 0)
{
fprintf(stderr, "process %d of %d sending data...\n", myid, nprocs);
MPI_Send(sb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD);
fprintf(stderr, "process %d of %d receiving data...\n", myid, nprocs);
MPI_Recv(rb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD, &status);
}
// Send and receive data in proc 1.
if (myid == 1)
{
fprintf(stderr, "process %d of %d sending data...\n", myid, nprocs);
MPI_Send(sb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD);
//fprintf(stderr, "process %d of %d receiving data...\n", myid, nprocs);
//MPI_Recv(rb, BUF_SIZE, MPI_INT, other, 1, MPI_COMM_WORLD, &status);
}
则输出的结果是:1
2
3
4
5
6
7[zjshao@master ch02]$ mpiexec -n 2 std_send_recv_2.x
process 1 of 2 sending data...
process 0 of 2 sending data...
Hello world, process 1 of 2
process 0 of 2 receiving data...
Hello world, process 0 of 2
[zjshao@master ch02]$
这个时候两个进程都自行结束了,这个应该就想到于发送动作遭遇接收动作,这个时候消息大小小于MPI的缓冲区大小,会将数据传输到MPI缓冲区中进行缓存,然后函数立即返回,这样进程就不会开在发送数据部分无法将程序的拥有权交给主程序。
但如果我将应用缓冲区大小增大,使其大于系统缓冲区大小,会出现什么情况呢?1
修改好编译执行:1
2
3
4
5
6
7[zjshao@master ch02]$ mpicc -std=c99 std_send_recv.c -o std_send_recv_2.x
[zjshao@master ch02]$ mpiexec -host node01 -n 2 std_send_recv_2.x
process 1 of 2 sending data...
process 0 of 2 sending data...
[mpiexec@master.cluster] Sending Ctrl-C to processes as requested
[mpiexec@master.cluster] Press Ctrl-C again to force abort
[zjshao@master ch02]$
以上就是我对阻塞通信中的标准通信模式的总结了。