Spread Knowledge

CS604 - Operating Systems - Lecture Handout 07

User Rating:  / 0
PoorBest 

Related Content: CS604 - VU Lectures, Handouts, PPT Slides, Assignments, Quizzes, Papers & Books of Operating Systems

Summary

  • The execlp(), wait(), and exec() system calls and sample code
  • Cooperating processes
  • Producer-consumer problem
  • Interprocess communication (IPC) and process synchronization

The wait() system call

The wait system call suspends the calling process until one of the immediate children terminate, or until a child that is being traced stops because it has hit an event of interest.
The wait will return prematurely if a signal is received. If all child processes stopped or terminated prior to the call on wait, return is immediate. If the call is successful, the process ID of a child is returned. If the parent terminates however all its children have assigned as their new parent, the init process. Thus the children still have a parent to collect their status and execution statistics. The synopsis of the wait system call is as follows:

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc);

A zombie process is a process that has terminated but whose exit status has not yet been received by its parent process or by init. Sample code showing the use of fork() and wait() system calls is given in Figure 7.1 below.

The wait() system call

The wait() system call 1

The execlp() system call

Typically, the execlp() system call is used after a fork() system call by one of the two processes to replace the process’ memory space with a new program. The new process image is constructed from an ordinary, executable file. This file is either an executable object file, or a file of data for an interpreter. There can be no return from a successful exec because the calling process image is overlaid by the new process image.
In this manner, the two processes are able to communicate and then go their separate ways. The synopsis of the execlp() system call is given below:

#include <unistd.h>
int execlp (const char *file, const,char *arg0, ...,
const char *argn,(char *)0);

Sample code showing the use of fork() and execlp() system calls is given in Figure 7.2 below.

code showing use of fork(), execlp(), wait(), and exit()

The semantics of fork(), followed by an execlp() system call are shown In Figure 7.3 below.

Semantics of fork() followed by exec()

Cooperating Processes

The concurrent processes executing in the operating system may be either independent processes or cooperating processes. A process is independent if it cannot affect or be affected by any other process executing in the system. Clearly any process that shares data with other processes is a cooperating process. The advantages of cooperating
processes are:

  • Information sharing: Since several users may be interested in the same piece of information (for instance, a shared file) we must provide an environment to allow concurrent users to access these types of resources.
  • Computation speedup: If we want a particular task to run faster, we must break it into subtasks each of which will be running in parallel with the others. Such a speedup can be obtained only if the computer has multiple processing elements (such as CPU’s or I/O channels).
  • Modularity: We may want to construct the system in a modular fashion, dividing the system functions into separate processes or threads.
  • Convenience: Even an individual user may have many tasks on which to work at one time. For instance, a user may be editing, printing, and compiling in parallel.

To illustrate the concept of communicating processes, let us consider the producer consumer problem. A producer process produces information that is consumed by a consumer process. For example, a compiler may produce assembly code that is consumed by an assembler. To allow a producer and consumer to run concurrently, we must have available a buffer of items that can be filled by a producer and emptied by a consumer. The producer and consumer must be synchronized so that the consumer does not try to consume an item that has not yet been produced. The bounded buffer problem assumes a fixed buffer size, and the consumer must wait if the buffer is empty and the producer must wait if the buffer is full, whereas the unbounded buffer places no practical limit on the size of the buffer. Figure 7.4 shows the problem in a diagram. This buffer may be provided by interprocess communication (discussed in the next section) or with the use of shared memory.

The producer-consumer problem

Figure 7.5 shows the shared buffer and other variables used by the producer and consumer processes.

producer and consumer processes

The shared buffer is implemented as a circular array with two logical pointers: in an out.
The ‘in’ variable points to the next free position in the buffer; ‘out’ points to the first full position in the buffer. The buffer is empty when in==out, the buffer is full when ((in+1)%BUFFER_SIZE)==out. The code structures for the producer and consumer processes are shown in Figure 7.6.

Code structures for the producer and consumer processes