# Send modes (MPI) `MPI_Send` has a behaviour that surprises many first-time users: whether it blocks or returns immediately depends on message size and the implementation's internal buffer. For small messages, most implementations copy the data into an internal buffer and return right away. For messages larger than that buffer, `MPI_Send` blocks until the receiver posts a matching `MPI_Recv`. Code that runs correctly with small test data can deadlock in production when message sizes grow, because the buffering that masked the cyclic dependency disappears. The four send modes exist to make this behaviour explicit and portable. `MPI_Ssend` (synchronous send) never buffers. It blocks until the receiver has posted a matching `MPI_Recv`, which makes it the most useful tool for debugging deadlocks: replacing `MPI_Send` with `MPI_Ssend` removes buffering as a variable, so if the code hangs it definitely has a cyclic dependency rather than just exceeding buffer limits. `MPI_Bsend` (buffered send) always returns immediately by copying into a user-supplied buffer attached with `MPI_Buffer_attach`. `MPI_Rsend` (ready send) asserts that a matching receive is already posted; behaviour is undefined if it is not, but it can skip handshake overhead on implementations that exploit the guarantee. ```c // synchronous: blocks until receiver has called MPI_Recv MPI_Ssend(&x, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); // buffered: always returns immediately; user manages the buffer char buf[MPI_BSEND_OVERHEAD + sizeof(int)]; MPI_Buffer_attach(buf, sizeof(buf)); MPI_Bsend(&x, 1, MPI_INT, dest, 0, MPI_COMM_WORLD); MPI_Buffer_detach(&buf_ptr, &buf_size); // blocks until buffer is drained ``` All four modes have non-blocking variants: `MPI_Issend`, `MPI_Ibsend`, `MPI_Irsend`. They follow the same request/wait pattern as `MPI_Isend`.