The sender sends a message that contains data and it is made in such a way that the receiver can understand it. The inter-process communication in distributed systems is performed using Message Passing. It permits the exchange of messages between the processes using primitives for sending and receiving messages.
1. A Fixed-Length Header with 3 Components:
- Address: The address component consists of a sender and receiving process unique addresses. It contains two parts: one part contains an address for sending process and the other part contains an address for receiving process.
- Sequence number: The sequence number works like Message Identifier (ID) as it is used in situations where we need to find missing or duplicate messages because of system failure.
- Structural Information: It contains two fields: The type (data or a pointer to data included) and the length of the message are structural information.
2. A Collection of Typed Data Objects of Varying Sizes:
Message Passing: A message-passing system gives a collection of message-based IPC (Inter-Process Communication) protocols while sheltering programmers from the complexities of sophisticated network protocols and many heterogeneous platforms. The send() and receive() communication primitives are used by processes for interacting with each other. For example, Process A wants to communicate with Process B then Process A will send a message with send() primitive and Process B will receive the message with receive() primitive.
Characteristics of a Good Message Passing System:
- Uniform Semantics
Issues in Message Passing:
- Who is the message’s sender?
- Who is the intended recipient?
- Is there a single receiver or several receivers?
- Is there any guarantee that the intended recipient received the message? Is it required to wait for the reply from the sender?
- Is there any strategy for handling a catastrophic event if it occurs during communication, such as a communication link failure or node crash?
- What should be done with the message if the receiver is not ready to take it? Whether it will be destroyed or kept in a buffer? What are the steps to follow if the buffer is also full in the case of buffering?
- Can a receiver be able to do the ordering of messages in case of several outstanding messages?
- The send() and receive() primitives are called whenever processes need to communicate.
- The communication primitives’ synchronization of communicative processes is a critical issue in the communication structure.
Synchronization Semantics: The following are the two ways of message passing between processes:
- Blocking (Synchronous)
- Non-blocking (Asynchronous)
1. Blocking: The blocking semantics implies that when the call of a send () or receive() primitive blocks the invoker’s current execution.
2. Non-blocking: The non-blocking semantics imply that when the call of a send () or receive() primitive does not block the invoker’s current execution and the control immediately goes back to the invoker.
- Blocking send() primitive: The blocking send() primitive refers to the blocking of sending process. The process remains blocking until it receives an acknowledgment from the receiver side that the message has been received after the execution of this primitive.
- Non-blocking send() primitive: The non-blocking send() primitive refers to the non-blocking state of the sending process that implies after the execution of send() statement, the process is permitted to continue further with its execution immediately when the message has been transferred to a buffer.
- Blocking receive() primitive: when they receive statement is executed, the receiving process is halted until a message is received.
- Nonblocking receive() primitive: The non-blocking receive() primitive implies that the receiving process is not blocked after executing the receive() statement, control is returned immediately after informing the kernel of the message buffer’s location.
The issue in a nonblocking receive() primitive is when a message arrives in the message buffer, how does the receiving process know? One of the following two procedures can be used for this purpose:
- Polling: In the polling method, the receiver can check the status of the buffer when a test primitive is passed in this method. The receiver regularly polls the kernel to check whether the message is already in the buffer.
- Interrupt: A software interrupt is used in the software interrupt method to inform the receiving process regarding the status of the message i.e. when the message has been stored into the buffer and is ready for usage by the receiver. So, here in this method, receiving process keeps on running without having to submit failed test requests.
In a blocked send() and receive() primitive, there is an issue:
- Blocking send() primitive: The issue that can be raised here is that the sending process may become permanently halted if receiving process has crashed or the sent messages are lost because of communication failure. So, blocking send() primitives have set a fixed time value which when elapsed send operation is halted with an error status to avoid this problem. Users might be given the option to specify the timeout value as a parameter of the send primitive, or it could be set as a default.
- Blocking receive() primitive: To avoid the receiving process from becoming halted indefinitely, a blocking receive() primitive might be connected with a fixed time value. This can happen if the prospective sending procedure fails or if the expected message is lost on the network owing to a communication breakdown.
Unlock the Power of Placement Preparation!
Feeling lost in OS, DBMS, CN, SQL, and DSA chaos? Our Complete Interview Preparation
Course is the ultimate guide to conquer placements. Trusted by over 100,000+ geeks, this course is your roadmap to interview triumph.
Ready to dive in? Explore our Free Demo Content and join our Complete Interview Preparation