Interprocess Communication, CPU Scheduling Flashcards
Interprocess Communication
- Processes within a system may be independent or cooperating
- Cooperating process can affect or be affected by other processes
- Reasons for cooperating processes:
- Information sharing
- Computation speedup
- Modularity
- Cooperating processes need interprocess communication (IPC)
- Two models of IPC
- Shared memory (require process synchronization)
- Message passing
Message Passing
Message Passing needs:
* Some way of addressing the message.
* Some way of transporting the message.
* Some way of notifying the receiver that a message has arrived.
* Some way of accessing or depositing the message in the receiver.
The message size is either fixed or variable
May look like:
send(destination, message)
receive(source, message)
Or:
write(message)
read(message)
In this case we also need some way of making a connection between the processes, like
an open() call.
Direct Communication
Processes must name each other explicitly:
* send (P, message) – send a message to process P
* receive(Q, message) – receive a message from process Q.
Properties of Direct Communication Link
- Links are established automatically
- One link between each pair of processes
- The link may be unidirectional, but is usually bi-directional
- receiver doesn’t have to know the id of the sender (it can receive it with the message)
- A server can receive from a group of processes
Disadvantages of Direct Communication
- Can’t easily change the names of processes.
- Could lead to multiple programs needing to be changed.
Indirect Communication
Messages are directed and received from mailboxes (also referred to as ports)
* Each mailbox has a unique id
* Processes can communicate only if they share a mailbox
* Mailbox ownership – system owned, or process owned
Properties of Indirect Communication Link
- Link established only if processes share a common mailbox
- A link may be associated with many processes
- Each pair of processes may share several communication links
- Link may be unidirectional or bi-directional
Oridinary Pipes (UNIX)
- Acts as a conduit allowing two processes to communicate
- In UNIX it starts as a way for a process to talk to itself.
int my_pipe[2]; pipe(my_pipe); - The system call returns two UNIX file descriptors
Data gets put into the pipe and taken out the other end - the write-end of the pipe – my_pipe [1]
- the read-end of the pipe – my_pipe [0]
- Use ordinary read() and write() system calls.
e.g., write(my_pipe[1], data, length); - Ordinary pipes are therefore unidirectional
- Cannot be accessed from outside the process that created it.
- Require parent-child relationship between communicating processes
- Windows calls these anonymous pipes
Empty and Full Pipes
- Reading process blocks when pipe is empty (until data becomes available)
- Writing process blocks when pipe is full (65536 bytes on recent Linuxes)
Broken Pipes
- A process waiting to read from a pipe with no writer gets an EOF (once all existing data has been
read). - A process writing to a pipe with no reader gets signalled.
- Writes are guaranteed to not be interleaved if they are smaller than the PIPE_BUF constant.
This must be at least 512 bytes and is 4096 bytes by default on Linux.
Limitations of Ordinary Pipes
- Can only be used to communicate between related processes. (Named pipes or FIFO files can be
used for unrelated processes.) - The file handles are just low integers which index into the file table for this process.
- The same numbers only make sense in the same process (or in one forked from it).
Named Pipes
- Named Pipes are more powerful than ordinary pipes
- Communication is bidirectional
- No parent-child relationship is necessary between the communicating processes
- Several processes can use the named pipe for communication
- Provided on both UNIX and Windows systems
Communicating via Shared Resources
Shared resources
* Separate processes can alter the resource.
* Need to check the state of the resource to either receive data or know that some
event has occurred.
* Usually need to explicitly coordinate access to the resource.
Files
* Easy to use but slow.
* File system may provide synchronization help, e.g., only one writer at a time.
Memory
* Fast
* Synchronization is usually handled explicitly by the processes.
Shared Memory
- Different threads in the same process automatically share memory.
- define sections of shared memory,
- attach the shared memory to the process,
- detach, indicate who can access it etc.
- Both processes need to know the name of the area of shared memory.
- Must make sure the memory is attached to some unused area of the process’s
address space.
Shared Memory in LINUX Processes
Remember that fork copies data.
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
void main() {
void *shared;
int *a_number;
int b_number;
shared = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
printf("Program 1 - shared:%p\n", shared);
a_number = (int *)shared;
printf("a_number: %d, b_number: %d\n", *a_number, b_number);
if (fork() != 0) {
*a_number = 12345;
b_number = 54321;
}
printf("a_number: %d, b_number: %d\n", *a_number, b_number);
}
Reading and writing to shared memory is done by using the pointer returned by mmap().</unistd.h></stdio.h>
POSIX Shared Memory
- Process first creates shared memory segment
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666); - Also used to open an existing segment
- Set the size of the object
ftruncate(shm_fd, 4096); //set size in bytes - Use mmap()to memory-map a file pointer to the shared memory object
- Reading and writing to shared memory is done by using the pointer returned by
mmap().
ptr = (char *) mmap(0, SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, shm_fd, 0);
Signals
Signals are used in UNIX systems to notify a process that a particular event has
occurred.
* A signal handler is used to process signals
1. Signal is generated by particular event
2. Signal is delivered to a process
3. Signal is handled by one of two signal handlers:
- default
- user-defined
Signal Handlers
Every signal has default handler that kernel runs when handling signal
* User-defined signal handler can override default
* For single-threaded, signal delivered to process
* For multi-threaded, depends on the type of signal generated
Signals - Software Interrupts
kill(pid, signalNumber)
* originally for sending events to the process because it had to stop.
- signalNumbers for:
- illegal instructions
- memory violations
- floating point exceptions
- children finishing
- job control
- But processes can catch and handle signals with signal handlers.
signal(signalNumber, handler) - Can also ignore or do nothing.
If you don’t ignore or set a handler, then getting a signal stops the process. - One signal can’t be handled - 9 SIGKILL
Mach Ports
- Underneath macOS and iOS
- Everything done via ports even system calls and exception handling
- Only one receiver from each port but can have multiple senders
(unidirectional too) - Can pass the right to receive
- When a process is started, it is given send rights to a port on the
bootstrap process (the service naming daemon) (and it normally gives the
bootstrap process send rights via a message) - Programmers don’t usually work at that level (they can use the standard
UNIX communication mechanisms)
Mach Port Processes
- Each task (or process) gets two ports at creation - Kernel and Notify
- Messages are sent and received using the mach_msg() function
- Ports needed for communication, created via
mach_port_allocate() - Send and receive are flexible; for example four options if mailbox full:
- Wait indefinitely
- Wait at most n milliseconds
- Return immediately
- Temporarily cache a message