我在发送和接收二维数组的列时遇到问题。
我有2个进程。第一个进程有一个二维数组,我想将它的一部分发送到第二个进程。所以说每个等级都有一个9x9阵列,我喜欢将等级0发送到等级1只是某些列:
示例:
-1--2--3-
-2--3--4-
-5--6--7-
...
我想发送" 1,2,5,..."和" 3,4,7,......"。
我已经编写了代码来发送第一列,并且我已经通读了this answer,并且我相信我已经为该列正确定义了MPI_Type_vector:
MPI_Type_vector(dime,1,dime-1,MPI_INT,&LEFT_SIDE);
这里的dime
,9,是数组的大小;我发送了9个1 MPI_INT的块,每个块以8的步幅分开 - 但即使只是发送这一列,也会给我无效的结果。
我的代码如下:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define dime 9
int main (int argc, char *argv[])
{
int size,rank;
const int ltag=2;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Get the rank of the process
int table[dime][dime];
for (int i=0; i<dime; i++)
for (int j=0; j<dime; j++)
table[i][j] = rank;
int message[dime];
MPI_Datatype LEFT_SIDE;
MPI_Type_vector(dime,1,dime-1,MPI_INT,&LEFT_SIDE);
MPI_Type_commit(&LEFT_SIDE);
if(rank==0) {
MPI_Send(table, 1, LEFT_SIDE, 1, ltag, MPI_COMM_WORLD);
} else if(rank==1){
MPI_Status status;
MPI_Recv(message, 1, LEFT_SIDE, 0, ltag, MPI_COMM_WORLD, &status);
}
if(rank == 1 ){
printf("Rank 1's received data: ");
for(int i=0;i<dime;i++)
printf("%6d ",*(message+i));
printf("\n");
}
MPI_Finalize();
return 0;
}
但是当我运行它并查看我收到的数据时,我会得到全部为零或乱码:
$ mpicc -o datatype datatype.c -Wall -g -O3 -std=c99
$ mpirun -np 2 datatype
Rank 1's received data: 0 32710 64550200 0 1828366128 32765 11780096 0 0
每次数字都会改变。我做错了什么?
答案 0 :(得分:4)
MPI数据类型描述了数据在内存中的布局方式。让我们看看你的2d数组是否有更小的dime
(比如4)和相应的MPI_Type_vector:
MPI_Type_vector(count=dime, blocksize=1, stride=dime-1, type=MPI_INT ...
= 4 =1 = 3
data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
Vector: X - - X - - X - - X - -
请注意,MPI类型中的步幅是类型的开始之间的距离,而不是它们之间的间隙大小;所以你实际上想要stride = dime,而不是dime-1。这很容易解决,但不是实际问题:
MPI_Type_vector(count=dime, blocksize=1, stride=dime, type=MPI_INT ...
= 4 =1 = 4
data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 };
Vector: X - - - X - - - X - - - X - - -
好的,到目前为止,我们正在选择正确的元素。但我们并没有正确地接收它们;试图将数据接收到大小角钱数组的代码,使用相同的布局:
int message[dime];
MPI_Recv(message, 1, LEFT_SIDE, 0, ...
message = { 0, 1, 2, 3 };
Vector: X - - - X - - - X - - - X - - -
向量远远超出了消息的范围,其中(a)在消息中留下未初始化的数据,这是乱码的来源,并且(b)可能导致超出数组边界的分段错误。
至关重要的是,其中一个MPI_Type_vectors描述了2d矩阵中所需数据的布局,但不描述了相同数据的布局,因为它接收到紧凑的1d数组中。
这里有两种选择。将数据作为message
发送到dime x MPI_INT
数组:
// ....
} else if(rank==1){
MPI_Status status;
MPI_Recv(message, dime, MPI_INT, 0, ltag, MPI_COMM_WORLD, &status);
}
//...
$ mpirun -np 2 datatype
Rank 1's received data: 0 0 0 0 0 0 0 0 0
或直接将数据直接接收到Rank 1的2d矩阵中,覆盖相应的列:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define dime 9
int main (int argc, char *argv[])
{
int size,rank;
const int ltag=2;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Get the rank of the process
int table[dime][dime];
for (int i=0; i<dime; i++)
for (int j=0; j<dime; j++)
table[i][j] = rank;
MPI_Datatype LEFT_SIDE;
MPI_Type_vector(dime,1,dime,MPI_INT,&LEFT_SIDE);
MPI_Type_commit(&LEFT_SIDE);
if(rank==0) {
MPI_Send(table, 1, LEFT_SIDE, 1, ltag, MPI_COMM_WORLD);
} else if(rank==1){
MPI_Status status;
MPI_Recv(table, 1, LEFT_SIDE, 0, ltag, MPI_COMM_WORLD, &status);
}
if(rank == 1 ){
printf("Rank 1's new array:\n");
for(int i=0;i<dime;i++) {
for(int j=0;j<dime;j++)
printf("%6d ",table[i][j]);
printf("\n");
}
printf("\n");
}
MPI_Type_free(&LEFT_SIDE);
MPI_Finalize();
return 0;
}
跑步给出
$ mpicc -o datatype datatype.c -Wall -g -O3 -std=c99
$ mpirun -np 2 datatype
Rank 1's new array:
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
(在更正MPI_Type_vector之后)
关于如何将其扩展到多列的剩余部分可能最好留给另一个问题。
答案 1 :(得分:2)
我不太清楚你的问题究竟是什么(请在你的问题中明确说明,你会得到更好的答案!另见How do I ask good questions。),但你的代码有几个的问题。
您需要使用public class MainActivity extends Activity {
private TextView prairText;
private AssetFileDescriptor descriptor;
private SeekBar seekBar;
private MediaPlayer mp = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Keep screen active
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
findViewById(R.id.play_button).setVisibility(View.INVISIBLE);
findViewById(R.id.pauseButton).setVisibility(View.VISIBLE);
init();
// Play prayer
/*if (mp != null) {
mp.start();
}*/
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mp != null && fromUser) {
mp.seekTo(progress * 1000);
}
}
});
findViewById(R.id.play_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mp != null) {
mp.start();
final Handler mHandler = new Handler();
//Make sure you update Seekbar on UI thread
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
if(mp != null){
int mCurrentPosition = mp.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
mHandler.postDelayed(this, 1000);
}
});
findViewById(R.id.play_button).setVisibility(View.INVISIBLE);
findViewById(R.id.pauseButton).setVisibility(View.VISIBLE);
}
}
});
findViewById(R.id.pauseButton).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mp != null) {
mp.pause();
findViewById(R.id.pauseButton).setVisibility(View.INVISIBLE);
findViewById(R.id.play_button).setVisibility(View.VISIBLE);
}
mp.pause();
}
});
findViewById(R.id.restart_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mp != null) {
mp.seekTo(0);
mp.start();
findViewById(R.id.play_button).setVisibility(View.INVISIBLE);
findViewById(R.id.pauseButton).setVisibility(View.VISIBLE);
}
}
});
private void init() {
prairText = (TextView) findViewById(R.id.prairText);
seekBar = (SeekBar) findViewById(R.id.seekBar1);
try {
descriptor = getAssets().openFd("mysong.mp3");
mp.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
descriptor.close();
mp.prepare();
} catch (Exception e) {
e.printStackTrace();
}
seekBar.setMax(mp.getDuration());
}
,因为您要发送矩阵的每一分钱元素。在C中,2-d数组简单地存储为标准数组,其中元素[i] [j]存储在索引[i * dime + j]。你想发送索引0,角钱,2 *角钱,3 *角钱,...
如果您使用MPI_Type_vector(dime,1,dime,MPI_INT,&LEFT_SIDE);
数据类型来接收数据,MPI将存储数据项与间隔元素的间隙 - 类似于发件人。但是,您的接收缓冲区LEFT_SIDE
是一个简单的数组。您需要接收如下数据:message
。此操作将接收一角硬币整数并将它们放入您的MPI_Recv(message, dime, MPI_INT, 0, LTAG, newcomm,&status);
数组中。
编辑:我更新了我的答案以匹配显着更改的问题。