The conceptually simplest send function in MPI is MPI_Bsend, or buffered send. It has the following prototype:
int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)MPI_Bsend sends the data pointed to by buf, which it assumes to be count elements of datatype datatype, to the process ranked dest in communicator comm. Additionally, it tags the message with the value tag. MPI_Bsend guarantees asynchronous message delivery in that it may complete before a corresponding receive is posted at the receiver. These semantics are implemented by the system buffering the message internally until a receive is posted. If there is not enough buffer space available at the time it is called, MPI_Bsend fails and returns an error.
MPI_Ssend performs a synchronous send, in that it guarantees synchronized message delivery. MPI_Ssend cannot complete before a corresponding receive to accept the message has been posted at the receiver. Hence, the message does not need to be buffered. Consequently, MPI_Ssend cannot fail, only block indefinitely until a receive gets posted.
MPI_Send performs either a synchronous or a buffered send. The decision to use a particular type of send can be made at runtime, and hence the programmer must be aware of both possibilities. Some implementations of MPI use a buffered send only when the message to be sent is small, and there is enough buffer space available. Under all other conditions, synchronous send is used.
MPI_Rsend, or ready send, actually performs a synchronous send, but the program must guarantee that a corresponding receive has already been posted at the receiver. In other words, if a receive has not already been posted, MPI_Rsend has been incorrectly used. MPI_Rsend is simply a way for implementors to optimize the communication protocol for messages for which it is known that receiver buffer space is already available. In other words, MPI_Ssend can always substitute an MPI_Rsend without affecting program semantics, and this is what is done in most current MPI implementations.
For each one of these calls, there is also a corresponding non-blocking call. For example, MPI_Ibsend (for immediate buffered send) is the non-blocking counterpart of MPI_Bsend. It initiates a buffered send and returns. It has the following prototype:
int MPI_Ibsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)request contains the handle for the operation initiated by MPI_Ibsend. This handle may be used by other function calls to check on the status of the operation. Upon completion of MPI_Ibsend, it is not guaranteed that the message has been copied out of buf and buffered by the system. Hence, the program cannot reuse buf until it checks for operation completion. In a similar way, upon the completion of MPI_Issend, it is not guaranteed that the message is being received by the receiver process.
The function call used to check for operation completion is MPI_Wait. It has the following prototype:
int MPI_Wait(MPI_Request *request, MPI_Status *status)Upon completion, status contains information on the completed operation. In general, any type of send operation is functionally equivalent to its non-blocking counterpart followed by MPI_Wait on the returned handle.