Learning Center
Plans & pricing Sign in
Sign Out
Your Federal Quarterly Tax Payments are due April 15th Get Help Now >>

Operating System Lec14CS604 (6)


									Operating Systems--[CS-604]                                                       Lecture No. 7

  Operating Systems
  Lecture No. 7

  Reading Material
         Operating Systems Concepts, Chapter 4
         UNIX/Linux manual pages for execlp(), exit(), and wait() system calls

         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
  #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.

                      #include <stdio.h>
                      void main(){
                        int pid, status;
                        pid = fork();
                        if(pid == -1) {
                         printf(“fork failed\n”);
                         if(pid == 0) { /* Child */
                            printf(“Child here!\n”);
                        else { /* Parent */
                           printf(“Well done kid!\n”);
                 Figure 7.1 Sample code showing use of the fork()
                            and wait() system calls

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.

 #include <stdio.h>
 void main()
   int pid, status;

    pid = fork();
    if(pid == -1) {
      printf(“fork failed\n”);
    if(pid == 0) { /* Child */
        if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
          printf(“exec failed\n”);
    else { /* Parent */
      printf(“Well done kid!\n”);
Figure 7.2 Sample 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.
 parent              parent                          parent

     P                   P                               P


                                            ls ls
    P                   P        exec                   ls
  child               child                           child
Figure 7.3 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.

                                 Empty Pool

    Producer                                                  Consumer

                                   Full Pool
Figure 7.4 The producer-consumer problem
   Figure 7.5 shows the shared buffer and other variables used by the producer and
consumer processes.
 #define BUFFER_SIZE 10
 typedef struct
 } item;
 item buffer[BUFFER_SIZE];
 int in=0;
 int out=0;

Figure 7.5 Shared buffer and variables used by the 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.
 Producer Process
 while(1) {
     /*Produce an item in nextProduced*/
     while(((in+1)%BUFFER_SIZE)==out); /*do nothing*/
 Consumer Process
 while(1) {
    while(in == out); //do nothing
    /*Consume the item in nextConsumed*/

Figure 7.6 Code structures for the producer and consumer processes


To top