Unit6 - Subjective Questions
CSE325 • Practice Questions with Detailed Answers
Define Inter-Process Communication (IPC) and explain why it is essential in an Operating System.
Definition:
Inter-Process Communication (IPC) refers to a set of mechanisms that allow processes to manage shared data or exchange data. It enables one process to control or notify another process about events.
Why it is essential:
- Information Sharing: Several users may need access to the same piece of information (e.g., shared files).
- Computation Speedup: A task can be broken into sub-tasks that run in parallel on multiple processors.
- Modularity: It allows constructing a system in a modular fashion (e.g., separating UI and backend logic).
- Convenience: Even a single user may work on multiple tasks at one time (e.g., editing, compiling, and printing).
Explain the working of the pipe() system call with its syntax and parameters.
The pipe() system call is used to create a unidirectional data channel that can be used for inter-process communication.
Syntax:
c
include <unistd.h>
int pipe(int pipefd[2]);
Parameters:
pipefd: An array of two integers.pipefd[0]refers to the read end of the pipe.pipefd[1]refers to the write end of the pipe.
Return Value:
- Returns 0 on success.
- Returns -1 on error.
Working: Data written to the write end of the pipe is buffered by the kernel until it is read from the read end. It follows a First-In-First-Out (FIFO) policy.
Differentiate between Unnamed Pipes and Named FIFOs.
| Feature | Unnamed Pipes | Named FIFOs (Named Pipes) |
|---|---|---|
| Existence | Exists only as long as the process is running. | Exists as a special file in the file system. |
| Scope | Can only be used between related processes (parent/child). | Can be used between unrelated processes on the same system. |
| Creation | Created using pipe() system call. |
Created using mkfifo() or mknod(). |
| Persistence | Disappears when the process terminates. | Persists in the file system until explicitly deleted. |
| Identification | Identified by file descriptors. | Identified by a filename/path. |
Write a C program snippet that demonstrates how a parent process sends a string message to a child process using a pipe.
c
include <stdio.h>
include <unistd.h>
include <string.h>
int main() {
int fd[2];
pid_t p;
char str[] = "Hello Child!";
char buffer[100];
// Create pipe
if (pipe(fd) == -1) {
perror("Pipe Failed");
return 1;
}
p = fork();
if (p < 0) {
perror("Fork Failed");
return 1;
} else if (p > 0) {
// Parent Process
close(fd[0]); // Close reading end
write(fd[1], str, strlen(str) + 1);
close(fd[1]); // Close writing end after done
} else {
// Child Process
close(fd[1]); // Close writing end
read(fd[0], buffer, 100);
printf("Child received: %s
", buffer);
close(fd[0]);
}
return 0;
}
Explain the concept of Shared Memory as an IPC mechanism. Why is it considered the fastest IPC method?
Concept:
Shared memory is an IPC mechanism that allows multiple processes to access the same portion of memory. One process creates a memory segment, and other processes can 'attach' this segment to their own address space. Changes made by one process are immediately visible to others.
Why it is the fastest:
- Zero-Copy: Unlike pipes or message queues, shared memory does not require data to be copied between the client and server processes or between the kernel and user space.
- Direct Access: Once the memory is mapped, processes access data directly as if it were a local variable, avoiding system call overheads for every read/write operation.
Describe the shmget() system call with its arguments and usage.
shmget() is used to create a shared memory segment or access an existing one.
Syntax:
c
include <sys/ipc.h>
include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Arguments:
key: A unique value (often generated usingftok()) used to identify the shared memory segment.size: The size of the shared memory segment in bytes (rounded up to page size).shmflg: Permissions and control flags (e.g.,IPC_CREAT | 0666creates the segment if it doesn't exist with read/write permissions).
Return Value:
- Returns a valid Shared Memory Identifier (shmid) on success.
- Returns -1 on failure.
What is the purpose of shmat()? Explain how it maps shared memory into a process's address space.
Purpose:
The shmat() (Shared Memory Attach) system call attaches a shared memory segment identified by shmid to the address space of the calling process.
Syntax:
c
void shmat(int shmid, const void shmaddr, int shmflg);
How it works:
shmid: Identifier returned byshmget.shmaddr: Specifies the address where to attach. IfNULL, the system chooses a suitable (unused) address.shmflg: Can be set toSHM_RDONLYto attach in read-only mode, or 0 for read/write.
Upon success, it returns a pointer to the attached shared memory block, allowing the process to read/write to it using standard pointer arithmetic.
Explain the significance of closing the unused ends of a pipe in a parent-child process communication scenario.
Closing unused pipe ends is crucial for proper functionality and resource management:
- EOF Generation: A process reading from a pipe will only receive an End-of-File (EOF) notification (return 0 from
read) when all write descriptors referring to that pipe are closed. If the reader keeps its own write end open (or the parent forgets to close it), theread()call will block indefinitely waiting for data, causing a deadlock. - SIGPIPE Signal: If a process writes to a pipe where all read ends are closed, the kernel sends a
SIGPIPEsignal to the writer, allowing it to handle the error (broken pipe) gracefully. - File Descriptor Exhaustion: Every open pipe end consumes a file descriptor. Failing to close them may lead to the process reaching the limit of open files.
How are Named FIFOs created programmatically and via the command line?
1. Command Line:
Using the mkfifo command:
bash
$ mkfifo my_pipe
This creates a special file named my_pipe in the current directory.
2. Programmatically (C Language):
Using the mkfifo() system call library function:
c
include <sys/types.h>
include <sys/stat.h>
// syntax: int mkfifo(const char *pathname, mode_t mode);
if (mkfifo("my_fifo", 0666) == -1) {
perror("mkfifo");
}
Here, 0666 sets the read/write permissions for the file.
Discuss the potential synchronization issues in Shared Memory and how they can be resolved.
Synchronization Issues:
Shared memory provides no built-in mechanism to prevent multiple processes from accessing the memory simultaneously. This leads to Race Conditions:
- Read-Write conflict: A reader might read data while a writer is partially through updating it, leading to inconsistent or corrupted data.
- Write-Write conflict: Two writers might overwrite each other's data simultaneously.
Resolution:
To resolve this, external synchronization primitives must be used to coordinate access:
- Semaphores: The most common method. A binary semaphore (mutex) locks the critical section during access.
- Mutex Locks/Condition Variables: Used if the shared memory is mapped into threads or via process-shared mutexes.
- Record Locking: Using
fcntl()on a file to coordinate access.
Explain the role of shmdt() and shmctl() in shared memory management.
1. shmdt() (Shared Memory Detach):
- Role: Detaches the shared memory segment from the address space of the calling process.
- Usage:
int shmdt(const void *shmaddr); - Effect: The process can no longer access the memory via the pointer, but the segment still exists in the OS kernel until explicitly deleted.
2. shmctl() (Shared Memory Control):
- Role: Performs control operations on a shared memory segment.
- Usage:
int shmctl(int shmid, int cmd, struct shmid_ds *buf); - Common Commands (
cmd):IPC_RMID: Marks the segment to be destroyed (deleted after the last process detaches).IPC_STAT: Retrieves the status of the segment.IPC_SET: Sets the status (permissions/ownership).
What is the specific behavior of opening a FIFO (Named Pipe) with O_RDONLY or O_WRONLY flags regarding blocking?
The behavior of open() on a FIFO depends on the flags used:
- O_RDONLY (Read Only): The call to
open()will block until some other process opens the same FIFO for writing. If a writer is already present, it returns immediately. - O_WRONLY (Write Only): The call to
open()will block until some other process opens the same FIFO for reading. - O_NONBLOCK:
- If specified with
O_RDONLY,openreturns immediately even if no writer exists. - If specified with
O_WRONLY,openreturns an error (-1witherrno=ENXIO) if no reader exists.
- If specified with
Write a C program that implements a writer process for Shared Memory. It should write "Operating Systems" into a shared segment.
c
include <sys/ipc.h>
include <sys/shm.h>
include <stdio.h>
include <string.h>
int main() {
// 1. Generate unique key
key_t key = ftok("shmfile", 65);
// 2. Create shared memory segment (1024 bytes)
int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
// 3. Attach to shared memory
char *str = (char*) shmat(shmid, (void*)0, 0);
// 4. Write data
printf("Write Data : ");
// In real scenario, user input or strcpy is used
strcpy(str, "Operating Systems");
printf("Data written in memory: %s
", str);
// 5. Detach from shared memory
shmdt(str);
return 0;
}
What happens if a process attempts to write to a pipe that is full, or read from a pipe that is empty?
Writing to a Full Pipe:
- Pipes have a limited capacity (buffer size, e.g., 64KB on Linux).
- If a process attempts to write to a pipe that is full, the
write()call will block (sleep) until sufficient space is cleared by a reader process reading data from the pipe.
Reading from an Empty Pipe:
- If a process attempts to read from a pipe that is currently empty, the
read()call will block until some data is written to the pipe by a writer process. - Exception: If the write end is closed,
read()returns 0 (EOF) instead of blocking.
Derive the necessity of the ftok() function in System V IPC (Shared Memory, Message Queues).
Necessity of ftok():
In System V IPC, resources (Shared Memory, Semaphores, Message Queues) are identified by a unique integer called a Key (key_t).
For two unrelated processes to communicate via shared memory, they must access the same segment. They cannot easily pass the integer ID to each other directly.
ftok() (File to Key) solves this by generating a unique key based on a common file path and a project ID.
Syntax:
Both processes call ftok() with the same existing filename and the same integer ID. This guarantees they generate the same key_t value, allowing them to connect to the same IPC resource.
Compare the performance overhead of Pipes versus Shared Memory.
Pipes (and FIFOs):
- Overhead: Higher.
- Mechanism: Data requires kernel intervention. Writing moves data from user space to kernel buffer; reading moves it from kernel buffer to user space.
- Data Copying: Involves at least two copy operations per message (User Kernel User).
- Context Switches: Often requires context switching between writer and reader.
Shared Memory:
- Overhead: Lowest.
- Mechanism: Once mapped, data access is treated as standard memory access.
- Data Copying: No data copying between kernel and user space is required for communication.
- Context Switches: Reduced, though synchronization (semaphores) adds slight overhead.
Conclusion: Shared Memory is significantly faster for large data transfers.
How can full-duplex communication be achieved using standard unnamed pipes?
Standard unnamed pipes are unidirectional (half-duplex). Data flows only from the write end to the read end.
To achieve full-duplex communication (simultaneous two-way communication) between a parent and a child process, two pipes are required.
Implementation Strategy:
- Create
Pipe A(fd1) andPipe B(fd2). - Parent Process:
- Writes to
Pipe A(fd1[1]). - Reads from
Pipe B(fd2[0]). - Closes fd1[0] and fd2[1].
- Writes to
- Child Process:
- Reads from
Pipe A(fd1[0]). - Writes to
Pipe B(fd2[1]). - Closes fd1[1] and fd2[0].
- Reads from
This creates two dedicated channels for traffic in opposite directions.
Define the term 'Atomic Operation' in the context of writing to a Pipe/FIFO.
Definition:
An atomic operation is an operation that appears to the rest of the system to occur instantaneously. In the context of pipes/FIFOs, it ensures data integrity during concurrent writes.
PIPE_BUF:
If a process writes data of size less than or equal to PIPE_BUF (defined in <limits.h>, typically 4KB or greater on Linux), the write is guaranteed to be atomic.
Implication:
If multiple processes write to the same FIFO simultaneously:
- If data size
PIPE_BUF: The data chunks from different writers will not be interleaved. One write completes fully before the next begins. - If data size
PIPE_BUF: The data may be interleaved with data from other writers.
Explain the significance of the IPC_PRIVATE key in shmget().
Significance:
IPC_PRIVATE is a special parameter used in place of a key generated by ftok when calling shmget.
- Usage:
shmget(IPC_PRIVATE, size, flags); - Behavior: It guarantees the creation of a new shared memory segment with a unique identifier.
- Use Case: It is typically used for IPC between a parent and a child process. The parent creates the segment using
IPC_PRIVATE, and the resultingshmidis inherited by the child process afterfork(). Since the child inherits the ID, no external key lookup is required. - Note: It does not mean the memory is private to one process; it simply ensures a new key space is used.
Describe the file permissions required for a process to perform IPC using Named Pipes.
Since Named Pipes (FIFOs) exist as files in the filesystem, they rely on standard UNIX file permissions (User/Group/Others).
- Creation: The process creating the FIFO (via
mkfifo) needs write permission on the directory where the FIFO is being created. - Access (Read/Write):
- The Reader process requires Read permission (
r) on the FIFO file. - The Writer process requires Write permission (
w) on the FIFO file.
- The Reader process requires Read permission (
Example 0666 in mkfifo:
rw-(User)rw-(Group)rw-(Others)
Allows read and write access to all users (subject toumask). Without appropriate permissions, theopen()call will fail withPermission denied.