1: //n为数组长度,p为进程数,id为进城id
2: #define BLOCK_LOW(id, p, n) ((id)*(n)/(p))
3: #define BLOCK_HIGH(id, p, n) (BLOCK_LOW((id)+1, p, n)-1)
4: #define BLOCK_SIZE(id, p, n) (BLOCK_HIGH(id, p, n) - BLOCK_LOW(id, p, n) + 1)
5: #define BLOCK_OWNER(j, p, n) (((P) * ((j) +1)-1)/(n))
并行程序为:
1: #include <stdlib.h>
2: #include <stdio.h>
3:
4: #include "mpi.h"
5: #include "my_mpi.h"
6: #include "common.h"
7: #include "sort/enum_sort.h"
8:
9: void mpi_sort(
10: int *argc,
11: char ***argv){ 12:
13: int process_id;
14: int process_size;
15:
16: int *count;
17: int *resp;
18:
19: int array_low;
20: int array_size;
21:
22: int *local_position;
23: int *position;
24:
25: int *sort_array;
26: int *init_array;
27: int array_length = ARRAY_LENGTH;
28:
29: int i;
30:
31: my_mpi_struct mpi_struct;
32:
33: mpi_start(argc, argv, &process_size, &process_id, MPI_COMM_WORLD);
34:
35: if(!process_id){ 36: position = (int *)my_mpi_malloc(0, sizeof(int) * array_length);
37: sort_array = (int *)my_mpi_malloc(0, sizeof(int) * array_length);
38: }
39:
40: init_array = (int *) my_mpi_malloc(process_id, sizeof(int) * array_length);
41: if(!process_id)
42: array_builder(init_array, array_length);
43:
44: MPI_Bcast(init_array, array_length, MPI_INT, 0, MPI_COMM_WORLD);
45:
46: array_low = BLOCK_LOW(process_id, process_size, array_length);
47: array_size = BLOCK_SIZE(process_id, process_size, array_length);
48:
49: get_my_mpi_struct(&mpi_struct, process_id, process_size, array_length);
50: get_resp_count_array(&resp, &count, mpi_struct);
51:
52: local_position = get_array_elem_position(init_array, array_length,
53: array_low, array_size);
54:
55: MPI_Gatherv(local_position, array_size, MPI_INT, position, count, resp,
56: MPI_INT, 0, MPI_COMM_WORLD);
57:
58: if(!process_id){ 59: for(i = 0; i< array_length; i++)
60: sort_array[position[i]] = init_array[i];
61:
62: printf("the result of mpi:\n"); 63: init_sort_array_print(init_array, sort_array, array_length);
64:
65: free(sort_array);
66: free(position);
67: }
68:
69: free(count);
70: free(resp);
71: free(local_position);
72: free(init_array);
73:
74: MPI_Finalize();
75: }
76:
其中mpi_start函数就是将编写MPI程序时三个必须函数MPI_Init,MPI_Comm_rank和MPI_Comm_size给写在一个函数中了,方便调用。
函数get_resp_count_array的作用是计算MPI收集函数所需要的偏移和组大小数组,其代码如下:
1: void get_resp_count_array(
2: int **resp, //the resp array
3: int **count, //the count array
4: my_mpi_struct mpi_struct){ //my mpi struct 5:
6: int i;
7:
8: int process_id = mpi_struct -> process_id;
9: int process_size = mpi_struct -> process_size;
10: int number_count = mpi_struct -> number_count;
11:
12: *resp = (int *)my_mpi_malloc(process_id, sizeof(int) * process_size);
13: *count = (int *)my_mpi_malloc(process_id, sizeof(int) * process_size);
14:
15: (*resp)[0] = 0;
16: (*count)[0] = BLOCK_SIZE(0, process_size, number_count);
17:
18: for(i = 1; i < process_size; i++){ 19: (*resp)[i] = (*resp)[i-1] + (*count)[i-1];
20: (*count)[i] = BLOCK_SIZE(i, process_size, number_count);
21: }
22: }
四、MPI主要函数说明
在本例中一共用到了两个主要的MPI函数:MPI_Bcast和MPI_Gatherv。即一个广播函数和一个收集函数。
MPI_Bcast是一个组通信操作,用来完成一个进程向通信域中所有的进程广播消息
MPI_Gatherv是完成收集的组通信函数。跟进程从进程i收集count[i]个元素,并将手机的i个元素放在接收缓冲区的resp[i]个位置开始的地方。
五、后记
这个MPI程序中一个比较简单的例子,作为我下MPI并行程序的一个开端。还请各位高手积极拍砖。
下篇将对快速排序的并行算法进行简单的介绍和实现。