MPI 函数说明 Dining philosophers哲学家进餐问题

MPI函数说明

  • (1)并行初始化函数:int MPI_Init(int *argc,char ***argv)
    参数描述:argc为变量数目,argv为变量数组,两个参数均来自main函数的参数

  • (2)并行结束函数: int MPI_Finalize()

  • (3)获得当前进程标识函数:int MPI_Comm_rank(MPI_Comm comm,int *rank)
    参数描述:comm为该进程所在的通信域句柄,rank为调用这一函数返回的进程在通信域中的标识号

  • (4)获取通信域包含的进程总数函数:int MPI_Comm_size(MPI_Comm comm,int *size)
    参数描述:comm为通信域句柄,size为函数返回的通信域comm内包含的进程总数

  • (5)获得本进程的机器名函数:int MPI_Get_processor_name(char *name,int *resultlen)
    参数描述:name为返回的机器名字符串,resultlen为返回的机器名长度

  • (6)消息发送函数:
    int MPI_Send(void *buf,int count,MPI_Datatype datatype,int dest,int tag,MPI_Comm comm)
    参数描述:buf为发送缓冲区的起始地址,count为将发送的数据个数(以后面的数据类型进行计数),datatype为发送数据的数据类型,dest为目的进程标识号,tag为消息标识,comm为通信域
    MPI_Send()将发送缓冲区buf中得count个datatype数据类型的数据发送到标识号为dest的目的进程,本次发送的消息标识是tag

  • (7)消息接收受函数:
    int MPI_Recv(void *buf,int count,MPI_Datatype datatype,int source,int tag,MPI_Comm,MPI_Status *status)
    参数描述:buf为接收缓冲区的起始地址,count为最多可接收的数据个数,datatype为接收数据的数据类型,source为接收数据的来源进程标识号,tag为消息标识,应与相应发送操作的标识相匹配,comm为本进程和发送进程所在的通信域,status为返回状态


实例


MPI_Send(
    void* data,
    int count,
    MPI_Datatype datatype,
    int destination,
    int tag,
    MPI_Comm communicator)

MPI_Recv(
    void* data,
    int count,
    MPI_Datatype datatype,
    int source,
    int tag,
    MPI_Comm communicator,
    MPI_Status* status)
  • Although this might seem like a mouthful when reading all of the arguments, they become easier to remember since almost every MPI call uses similar syntax.
    • The first argument is the data buffer. The second and third arguments describe the count and type of elements that reside in the buffer. MPI_Send sends the exact count of elements, and MPI_Recv will receive at most the count of elements (more on this in the next lesson).
    • The fourth and fifth arguments specify the rank of the sending/receiving process and the tag of the message. The sixth argument specifies the communicator and the last argument (for MPI_Recv only) provides information about the received message.

int token;
if (world_rank != 0) {
    MPI_Recv(&token, 1, MPI_INT, world_rank - 1, 0,
             MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    printf("Process %d received token %d from process %d\n",
           world_rank, token, world_rank - 1);
} else {
    // Set the token's value if you are process 0
    token = -1;
}
MPI_Send(&token, 1, MPI_INT, (world_rank + 1) % world_size,
         0, MPI_COMM_WORLD);

// Now process 0 can receive from the last process.
if (world_rank == 0) {
    MPI_Recv(&token, 1, MPI_INT, world_size - 1, 0,
             MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    printf("Process %d received token %d from process %d\n",
           world_rank, token, world_size - 1);
}

The ring program initializes a value from process zero, and the value is passed around every single process. The program terminates when process zero receives the value from the last process. As you can see from the program, extra care is taken to assure that it doesn’t deadlock. In other words, process zero makes sure that it has completed its first send before it tries to receive the value from the last process. All of the other processes simply call MPI_Recv (receiving from their neighboring lower process) and thenMPI_Send (sending the value to their neighboring higher process) to pass the value along the ring.MPI_Sendand MPI_Recv will block until the message has been transmitted. Because of this, the printfs should occur by the order in which the value is passed. Using five processes, the output should look like this.

Process 1 received token -1 from process 0
Process 2 received token -1 from process 1
Process 3 received token -1 from process 2
Process 4 received token -1 from process 3
Process 0 received token -1 from process 4

github_tutorials

http://mpitutorial.com/tutorials/


哲学家进餐问题, 无死锁

Using MPI to solve the Dining philosophers problem

/* 
  Compile:
    mpic++ philosophers.cpp -o philosophers
  Use:
    mpiexec -np 6 philosophers
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include "mpi.h"

void philosopher( int );
void table( int, int );
#define FORK_REQUEST 1
#define FORK_RESPONSE 2
#define FORK_RELEASE 3
#define DEBUG 1

int main(int argc, char** argv) {
    int myrank, nprocs;
    //init MPI
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

    //Depending on rand, Philosopher or Table
    if(myrank == 0) table(myrank, nprocs);
    else philosopher(myrank);

    MPI_Finalize();
    return 0;
}

/* Philosopher function - only philosopher processes run this */
void philosopher(int myrank){
    if(DEBUG) printf("Hello from philosopher %d \n", myrank);
    int in_buffer[1];
    int out_buffer[1];
    MPI_Status stat;
    out_buffer[0];
    srand (time(NULL) + myrank);

    //Philosopher main loop
    while(true){

        if(DEBUG) printf("Philosopher %d is sleeping \n", myrank);
        sleep(rand()%10); //Sleep
        if(DEBUG) printf("Philosopher %d is whaiting to eat \n", myrank);

        MPI_Send(out_buffer, 1, MPI_INT, 0, FORK_REQUEST, MPI_COMM_WORLD); //Request forks
        MPI_Recv(in_buffer, 1, MPI_INT, 0, FORK_RESPONSE, MPI_COMM_WORLD, &stat); //Whait for response
        if(DEBUG) printf("Philosopher %d is eating \n", myrank);
        sleep(rand()%10); //Eat
        if(DEBUG) printf("Philosopher %d is done eating \n", myrank);
        MPI_Send(out_buffer, 1, MPI_INT, 0, FORK_RELEASE, MPI_COMM_WORLD); //Release forks

    }
}

/* Table function - only table process run this */
void table(int myrank, int nprocs){
    printf("Hello from table %d \n", myrank);
    int in_buffer[1];
    int out_buffer[1];
    int philosopher;
    MPI_Status stat;

    std::list<int> queue;

    bool fork[nprocs-1];
    for(int i = 0; i < nprocs-1; i++) fork[i] = true; //Init all forks as free

    //Table main loop
    while(true){
        MPI_Recv(in_buffer, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG , MPI_COMM_WORLD, &stat); // Recive next message
        philosopher = stat.MPI_SOURCE; //Read source of message

        if(stat.MPI_TAG == FORK_REQUEST){ //If Request for forks
            if(DEBUG) printf("Table got philosopher %d fork request\n", philosopher);
            if(fork[philosopher%(nprocs-1)] == true && fork[philosopher-1] == true){ //If both forks are free
                fork[philosopher%(nprocs-1)] = false; //Set the forks as taken
                fork[philosopher-1] = false;
                MPI_Send(out_buffer, 1, MPI_REAL, philosopher, FORK_RESPONSE, MPI_COMM_WORLD); // Send Fork response to the right philosopher
                if(DEBUG) printf("Table sent philosopher %d the forks\n", philosopher);
            }
            else //If not both forks are free
                queue.push_back(philosopher); //Put in wait queue
        }
        if(stat.MPI_TAG == FORK_RELEASE){ //If Release of forks
            fork[philosopher%(nprocs-1)] = true; //Set forks to free again
            fork[philosopher-1] = true;
            if(DEBUG) printf("Table got philosopher %d fork release\n", philosopher);

            if(!queue.empty()){ //If philosopher whaiting for forks
                for (std::list<int>::iterator it = queue.begin(); it != queue.end(); it++){ //Go through whole list of whaiting philosophers
                    philosopher = *it;
                    if(fork[philosopher%(nprocs-1)] == true && fork[philosopher-1] == true){ //If one of them can get both forks
                        fork[philosopher%(nprocs-1)] = false;
                        fork[philosopher-1] = false;
                        MPI_Send(out_buffer, 1, MPI_INT, philosopher, FORK_RESPONSE, MPI_COMM_WORLD); // send Fork response
                        if(DEBUG) printf("Table sent philosopher %d the forks\n", philosopher);
                        it = queue.erase(it); //Remove from wait list
                    }
                }
            }
        }
    }   
}
posted @ 2016-06-06 09:55  panty  阅读(372)  评论(0编辑  收藏  举报