▶《并行程序设计导论》第三章(用 MPI 进行分布式内存编程)的第一个程序样例。

●  代码

 #include <stdio.h>
#include <string.h>
#include <mpi.h> const int maxSize = ; // 传输数据的最大尺寸,单位是个而不是字节 int main(int argc, char* argv[])
{
char greet[maxSize];
int size, rank;
MPI_Init(&argc, &argv); // MPI 初始化
MPI_Comm_size(MPI_COMM_WORLD, &size); // 获取通信子进程总数
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // 获取当前通信子的编号 if (rank != ) // 非主进程
{
sprintf_s(greet, maxSize, "\nGreet from process %d of %d", rank, size);
MPI_Send(greet, strlen(greet) + , MPI_CHAR, , , MPI_COMM_WORLD); // 发送信息给 0 号通信子
}
else // 主进程
{
char name[maxSize];
int nameLength;
MPI_Get_processor_name(name, &nameLength); // 获取主机名
printf("\nGreet from process %d of %d in %s (length:%d)", rank, size, name, nameLength);
for (int q = ; q < size; q++)
{
MPI_Recv(greet, maxSize, MPI_CHAR, q, , MPI_COMM_WORLD, MPI_STATUS_IGNORE);// 按顺序接受来自其他通信子的信息
printf("%s", greet);
}
}
MPI_Finalize(); // MPI 资源释放
//getchar(); // 不用添加 getchar();,程序在命令提示符中用 mpiexec 命令运行
return ;
}

● 输出结果,使用 mpiexec 命令执行

// 使用 q 按顺序接收信息
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec MPIProjectTemp.exe -n Greet from process of in CUAN (length:)
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of // 使用 MPI_ANY_SOURCE 乱序接收信息
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec MPIProjectTemp.exe -n Greet from process of in CUAN (length:)
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of

▶ 涨姿势

● 函数 MPI_Init(),接收参数列表以初始化 MPI,使用的参数见后面的 mpiexec 用法部分。在使用默认参数初始化的时候可以用 MPI_Init(NULL, NULL);

 MPI_Init(int *argc_p, ***argv_p);

● 函数 MPI_Comm_size() 和 MPI_Comm_rank(),指定通信子,并传入一个整数指针,返回该通信子的进程尺寸,或当前进程的编号。MPI_Comm 实际上是一个整形,见后面的宏定义部分。

 MPI_METHOD MPI_Comm_size(_In_ MPI_Comm comm, _Out_ _Deref_out_range_(> , ) int* size);

 MPI_METHOD MPI_Comm_rank(_In_ MPI_Comm comm, _Out_ _Deref_out_range_(>= , )  int* rank);

● 函数 MPI_Send() 。采用两种实现,一种是将消息发送至缓冲区后函数返回,继续执行接下去的语句,如果缓冲区中的消息等待接收的时间超过阈值,再阻塞发送端,通常较少的消息使用这种模式;另一种是阻塞发送消息的函数,直到消息被接收为止。下面几种发送函数的参数都相同。

● 函数 MPI_Ssend()(同步通信模式)发送进程把缓冲区填充完毕,且接收进程开始接收时,发送函数返回。参考(https://blog.csdn.net/weixin_42742438/article/details/83104578)

● 函数 MPI_Bsend()(缓存通信模式)用户保证发送进程缓冲区可用,发送函数返回与接收进程无关

● 函数 MPI_Rsend()(就绪通信模式)接收进程开始接收时,发送进程才开始发送(填充缓冲区之前)

● 函数 MPI_Isend()(非阻塞通信模式)发送进程提交发送请求后立即返回,与缓冲区填充、接收进程无关,多一个 MPI_Request *request 参数用于标记任务

 MPI_METHOD MPI_Send(
_In_opt_ const void* buf, // 指向发送数据的指针,转换为 void*
_In_range_(>= , ) int count, // 发送数据尺寸,1 表标量,超过 1 表数组长度
_In_ MPI_Datatype datatype, // 数据类型,注意使用 MPI 内建类型标志,见宏定义部分
_In_range_(>= , MPI_PROC_NULL) int dest,// 目标进程号
_In_range_(>= , ) int tag, // 数据标签,用于区分同一发送者和接受者之间传递的不同信息
_In_ MPI_Comm comm // 指定通信子
);

● 函数 MPI_Recv() 。其中,参数 source 可以使用 MPI_ANY_SOURCE,参数 tag 可以使用 MPI_ANY_TAG,以接收任意进程发送的,或带有任意标签的信息。在不需要使用参数 status 时可以将其设为默认值 MPI_STATUS_IGNORE。有类似的 MPI_Brecv(),MPI_Rrecv(),MPI_Irecv()

 MPI_METHOD MPI_Recv(
_Out_opt_ void* buf, // 指向接收数据的指针,转换为 void*
_In_range_(>= , ) int count, // 接收数据尺寸,1 表标量,超过 1 表数组长度,可以大于发送的数据大小
_In_ MPI_Datatype datatype, // 数据类型,注意使用 MPI 内建类型标志
_In_range_(>= , MPI_ANY_SOURCE) int source, // 数据源进程号
_In_range_(>= , MPI_ANY_TAG) int tag, // 数据标签
_In_ MPI_Comm comm, // 指定通信子
_Out_ MPI_Status* status // 给定一个状态结构指针,包含传递数据的来源,大小,标签等信息,见宏定义部分
);

● 函数 MPI_Get_count() 。在函数 MPI_Recv() 使用 MPI_ANY_SOURCE 或 MPI_ANY_TAG 的情况下,完成消息传递后不知道发送来源、数据量大小、数据标签,这时可以使用状态结构指针来获取相关信息。

 // 函数 MPI_Get_count() 的参数
MPI_METHOD MPI_Get_count(
_In_ const MPI_Status* status, // 状态结构指针
_In_ MPI_Datatype datatype, // 传递数据类型
_mpi_out_(count, MPI_UNDEFINED) int* count // 获取真实传递数据量
); // 使用范例
{
MPI_Status* status; // 创建一个状态结构指针
int count, source, tag, error;
MPI_Datatype dataType = MPI_INT; // 数据类型
MPI_Recv((void *)&data, , dataType, , , MPI_COMM_WORLD, status); // 接收数据
MPI_Get_count(status, dataType, &count); // 获得真实接受的数据量
source = status->MPI_SOURCE; // 获得数据来源进程号
tag = status->MPI_TAG; // 获得数据来源标签
error = status->MPI_ERROR; // 获得错误编号
}

● 用到的各种宏的定义

 // mpi.h
typedef int MPI_Datatype; // MPI 传输数据类型(缓冲区类型)
#define MPI_DATATYPE_NULL ((MPI_Datatype)0x0c000000)
#define MPI_CHAR ((MPI_Datatype)0x4c000101)
#define MPI_UNSIGNED_CHAR ((MPI_Datatype)0x4c000102)
#define MPI_SHORT ((MPI_Datatype)0x4c000203)
#define MPI_UNSIGNED_SHORT ((MPI_Datatype)0x4c000204)
#define MPI_INT ((MPI_Datatype)0x4c000405)
#define MPI_UNSIGNED ((MPI_Datatype)0x4c000406)
#define MPI_LONG ((MPI_Datatype)0x4c000407)
#define MPI_UNSIGNED_LONG ((MPI_Datatype)0x4c000408)
#define MPI_LONG_LONG_INT ((MPI_Datatype)0x4c000809)
#define MPI_LONG_LONG MPI_LONG_LONG_INT
#define MPI_FLOAT ((MPI_Datatype)0x4c00040a)
#define MPI_DOUBLE ((MPI_Datatype)0x4c00080b)
#define MPI_LONG_DOUBLE ((MPI_Datatype)0x4c00080c)
#define MPI_BYTE ((MPI_Datatype)0x4c00010d)
#define MPI_WCHAR ((MPI_Datatype)0x4c00020e) typedef int MPI_Comm; // 通信子类型
#define MPI_COMM_NULL ((MPI_Comm)0x04000000)
#define MPI_COMM_WORLD ((MPI_Comm)0x44000000)
#define MPI_COMM_SELF ((MPI_Comm)0x44000001) typedef struct MPI_Status // 用于保存信息传递元数据的结构
{
int internal[]; int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR; } MPI_Status; // 状态结构指针默认参数和两个 ANY 的定义
#define MPI_STATUS_IGNORE ((MPI_Status*)(MPI_Aint)1) #define MPI_ANY_SOURCE (-2)
#define MPI_ANY_TAG (-1)

● 命令提示符中 mpiexec 的用法(关于 -a 和 -aa 的没看懂,以后补充)

 mpiexec 的用法:
① mpiexec [options] executable [args] [ : [options] exe [args] : ... ]
② mpiexec -configfile <file name> 选项:
-configfile <file_name>
■ 从文件 <file_name> 中读取 mpiexec 的命令行,格式类似用法 ①,[options] executable [arguments],可用 '\' 转行,用 '#' 行注释 -optionfile <file_name>
■ 从文件 <file_name> 中读取 mpiexec 的选项,即作为命令行的一部分,格式 [option ] [option ] ... [option n],可用 '\' 转行,用 '#' 行注释 -n <num_processes>
-np <num_processes>
■ 指定运行的总进程数为 <num_processes> -n *
-np *
■ 指定运行的总进程数等于核心数,这是 -n -np 选项的默认参数。注意这里和下文中所有核心数均指逻辑核心数,而非物理核心数 -machinefile <file_name>
■ 运行主机的列表,格式为每行一个主机名,可选后跟该主机的核心数,用 '#' 行注释,-n * 默认使用的总进程数等于该列表中各主机核心数之和 -host <host_name>
■ 在名为 <host_name> 的主机上运行,-n * 默认使用一个核心 -hosts n host1 [m1][,mask[:group]] host2 [m2] ... hostn [mn]
■ 指定 n 台主机运行,并列出每台主机的名字和运行的进程数(默认为 ),同时可以使用 affinity masks 来指定每个核心上的进程数,参数 group 在大于 核心的系统中可用 -c <num_processes>
-cores <num_processes>
■ 指定每台主机上运行的核心数,该参数将覆盖选项 -hosts 或 -machinefile 指定的核心数数据 -a
-affinity
Set the affinity mask to a single core for each of the launched processes,
spreading them as far as possible throughout the available cores. This is the
equivalent of using the "-affinity_layout spr:L" option. -al <algo>[:<target>]
-al <algo>[:<stride>:<target>]
-affinity_layout <algo>[:<target>]
-affinity_layout <algo>[:<stride>:<target>]
Set the algorithm used to distribute launched processes to the compute cores,
and optionally specify the stride and the affinity target. The process
affinity is set to the specified target. Setting the stride in addition to
the target provides finer granularity (for example, "spr:P:L" will spread
processes across physical cores, and will bind each process to a single
logical core). If no stride is specified, it is assumed to be the same as the
target (for example, "seq:p" is the same as "seq:p:p"). Specifying affinity
with this option overrides any setting for the MPIEXEC_AFFINITY environment
variable. The following table lists the values for the <algo> parameter:
Value Description
-------- -----------------------------------------------------------------
No affinity (overrides any setting for MPIEXEC_AFFINITY).
or spr Spread: Distribute the processes as far as possible. (Default)
or seq Sequential: Distribute the processes sequentially.
or bal Balanced: Distribute the processes over the available NUMA nodes. The following table lists the values for the <target> and <stride> parameters:
Value Description
-------- -----------------------------------------------------------------
l or L Assign each process to a logical core. (Default)
p or P Assign each process to a physical core.
n or N Assign each process to a NUMA node. -aa
-affinity_auto
affinity_auto complements affinity_layout's behavior. It targets the
case where multiple jobs are running on the same node. When it is set, mpiexec
- Reads in the affinity settings which are published by other jobs running
on the same node, and determines the cores that are in use.
- Runs the specified MPIEXEC_AFFINITY algorithm avoiding the cores that are
in use, and calculates the affinity setting for this job.
- Publishes the calculated affinity settings so that upcoming jobs can avoid
the cores that are in use.
This way, multiple jobs on the same node can use the cores in a mutually exclusive
manner. -dir <working_directory>
-wdir <working_directory>
■ 指定工作空间,不超过 字符,可以使本地或者远端路径,包含需要的环境变量 -env <env_var_name> <env_var_value>
■ 指定环境变量 -genvlist <env_var_name1>[,env2,env3,...]
■ 将环境变量 <env_var_name1> 的值传递给 env2,env3 等环境变量,格式为逗号分隔。相当于统一环境变量 -exitcodes
■ 输出各进程的退出码 -priority {-}
■ 指定个进程额优先级, = idle, = below,=normal,=above,=high,默认为 -priority normal -p <port>
-port <port>
■ 指定 smpd 的监听端口 -path <path1>[;<path2>...]
■ 指定目标主机上的查找路径,多个路径之间用 ';' 分割,不影响环境变量 PATH 的值 -timeout <seconds>
■ 指定超时时限 -job <string>
■ 将应用程序与 Windows HPC 服务器创建的作业相关联 -l
-lines
■ 各进程输出时最前面写上进程号 -d [level]
-debug [level]
■ 将 debug 信息写入 stderr, = none, = error, = debug, = both,默认选项为 -d -genv, -gpath, -gdir, -gwdir, -ghost, -gmachinefile
■ 对应的无 g 选项的全局版本, -pwd <string>
■ 授权密码,仅当使用 MS-MPI Launch 服务时有效 -saveCreds
■ 保存密码凭据,在使用 -pwd 选项后可以保存密码,以后就不用再次授权密码,除非密码发生改变 -unicode
■ 要求运行输出支持 Unicode,可执行程序的路径等默认就支持 -?
-help
■ 列出简单的 mpiexec 的选项 -??
-help2
■ 列出帮助信息 -???
-help3
■ 列出环境变量

MPI Hello World的更多相关文章

  1. 查找素数Eratosthenes筛法的mpi程序

    思路: 只保留奇数 (1)由输入的整数n确定存储奇数(不包括1)的数组大小: n=(n%2==0)?(n/2-1):((n-1)/2);//n为存储奇数的数组大小,不包括基数1 (2)由数组大小n.进 ...

  2. kmeans算法并行化的mpi程序

    用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很赏心悦目~ 并行化思路: 使用主从模式.由一个节点充当主节点负责数据的划分与分配,其他节点完成本地 ...

  3. MPI Maelstrom - POJ1502最短路

    Time Limit: 1000MS Memory Limit: 10000K Description BIT has recently taken delivery of their new sup ...

  4. MPI之求和

    // MPI1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "mpi.h" #include &l ...

  5. VS2012下配置MPI

    并行处理结课实验,要用到MPI编程,我的电脑和VS2012都是64位的,以为MPICH也得是64位才行,结果饶了很大的弯——配置正确,添加引用之后,仍然无法识别MPI函数. 后来换了个32位的MPIC ...

  6. MPI+WIN10并行试运行

    系统:2015 win10专业版 x64 MPI安装包:mpich2-1.4.1p1-win-x86-64.man 将后缀改为.msi 以管理员身份安装 安装过程一路默认,注意<behappy为 ...

  7. Parallel Computing–Cannon算法 (MPI 实现)

    原理不解释,直接上代码 代码中被注释的源程序可用于打印中间结果,检查运算是否正确. #include "mpi.h" #include <math.h> #includ ...

  8. 基于MPI的并行计算—矩阵向量乘

    以前没接触过MPI编程,对并行计算也没什么了解.朋友的期末课程作业让我帮忙写一写,哎,实现结果很一般啊.最终也没完整完成任务,惭愧惭愧. 问题大概是利用MPI完成矩阵和向量相乘.输入:Am×n,Bn× ...

  9. 大数据并行计算利器之MPI/OpenMP

    大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...

  10. C++程序中调用MPI并行的批处理命令

    问题来源:在使用MPI时,将程序并行实现了,运行时需要在dos窗口下输入批处理命令,以完成程序的执行. 如:mpiexec -localroot -n 6 d:/mpi/pro.exe 但每次这样挺麻 ...

随机推荐

  1. php-fpm简介

    What is PHP-FPM? PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with ...

  2. 动态绑定AJAX,获取下级分类并延迟执行

    HTML: <div id='allType'> <div class='allTypeHead'><span>所有分类</span></div& ...

  3. System.out.println()详解 和 HttpServletRequest 和 XMLHttpRequest

    System是一个类,位于java.lang这个包里面.out是这个System类的一个PrintStream类型静态属性.println()是这个静态属性out所属类PrintStream的方法. ...

  4. apache spark kubernets 部署试用

    spark 是一个不错的平台,支持rdd 分析stream 机器学习... 以下为使用kubernetes 部署的说明,以及注意的地方 具体的容器镜像使用别人已经构建好的 deploy yaml 文件 ...

  5. C# 线程会合实例

    有这样一个题目:四个线程t1,t2,t3,t4,向4个文件中写入数据,要求:t1只能写入“1”,t2只能写入“2”,t3只能写入“3”,t4只能写入“4”,对4个文件A,B,C,D写入如下内容: A: ...

  6. CentOS 7防火墙开放端口快速方法

    这篇文章主要为大家详细介绍了Centos7.1防火墙开放端口的快速方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下   例如安装Nagios后,要开放5666端口与服务器连接,命令如下: [ro ...

  7. C语言面试题5

    C语言面试宝典 第一部分:基本概念及其它问答题 1.关键字static的作用是什么? 这个简单的问题很少有人能回答完全.在C语言中,关键字static有三个明显的作用: 1). 在函数体,一个被声明为 ...

  8. Linux下远程备份、上传工程,重启服务器

    Linux下远程备份.上传工程,重启服务器 Linux服务器实现远程,原项目的备份.删除,新项目上传,以及远程重启服务器!分成一个主shell调用三个shell文件步骤完成.mainsh.sh一次按顺 ...

  9. script 标签的defer,async的作用,及拓展浏览器多线程,DOMContentLoaded

    前端优化有一点就是优化js的执行时机,一般做法是将script放置于body的结束标签,以避免加载执行js 文件导致页面渲染阻塞的问题这种做法确实能防止页面阻塞,但是在页面渲染完成之后才去加载js文件 ...

  10. [C++ Primer] : 第10章: 泛型算法

    概述 泛型算法: 称它们为"算法", 是因为它们实现了一些经典算法的公共接口, 如搜索和排序; 称它们是"泛型的", 是因为它们可以用于不同类型的元素和多种容器 ...