Procesess

 

Process in Memory

 

 

As a process executes, it changes state

§  new:  The process is being created

§  running:  Instructions are being executed

§  waiting:  The process is waiting for some event to occur

§  ready:  The process is waiting to be assigned to a processor

§  terminated:  The process has finished execution

Diagram of Process State

 

 

Process Control Block (PCB

Information associated with each process

 

 

CPU Switch from Process to Process

 

Process Scheduling Queues

§  Job queue – set of all processes in the system

§  Ready queue – set of all processes residing in main memory, ready and waiting to execute

§  Device queues – set of processes waiting for an I/O device

Processes migrate among the various queues

 

Representation of Process Scheduling

 

Schedulers

§  Long-term scheduler (or job scheduler) – selects which processes should be in the ready queue

§  Short-term scheduler  (or CPU scheduler) – selects which process should be allocated the CPU

Ř Short-term scheduler is invoked very frequently (milliseconds) Ţ (must be fast)

Ř Long-term scheduler is invoked very infrequently (seconds, minutes) Ţ (may be slow)

Ř The long-term scheduler controls the degree of multiprogramming

Ř Processes can be described as either:

o   I/O-bound process – spends more time doing I/O than computations, many short CPU bursts

o   CPU-bound process – spends more time doing computations; few very long CPU bursts

Context Switch

§  When CPU switches to another process, the system must save the state of the old process and load the saved state for the new process via a context switch

§  Context of a process represented in the PCB

§  Context-switch time is overhead; the system does no useful work while switching

Process Creation

·       Parent process create children processes, which, in turn create other processes, forming a tree of processes

·       Generally, process identified and managed via a process identifier (pid)

·       Execution

§  Parent and children execute concurrently

§  Parent may waits until children terminate

 

·       Address space

§  Child duplicate of parent

§  Child may load new program.

 

·       UNIX examples

§  fork system call creates new process

§  exec system call used after a fork to replace the process’ memory with a new program

 

EXAMPLE:

newproc-posix.c

int main()

{

    pid_t  pid;

    pid = fork();

    if (pid == 0) { /* child process */

         execlp("/bin/ls", "ls", NULL);

    }

    else { /* parent process */

         wait (NULL);

         printf ("Child Complete");

         exit(0);

    }

}

 

«   To execute:

 

% newproc-posix

 

 

 


Interprocess Communication

§  Processes within a system may be independent or cooperating

§  Cooperating process can affect or be affected by other processes, including sharing data

§  Reasons for cooperating processes:

ü Information sharing

ü Computation speedup

ü Modularity

ü Convenience      

§  Cooperating processes need InterProcess Communication (IPC)

§  Examples of IPC

ü Shared memory

ü Message passing

Producer-Consumer Problem

Paradigm for cooperating processes,

producer process produces information that is consumed by a consumer process

§  unbounded-buffer places no practical limit on the size of the buffer

§  bounded-buffer assumes that there is a fixed buffer size

 

Bounded-Buffer – Shared-Memory Solution

Shared data:

 

 

#define BUFFER_SIZE 10

 

typedef struct {

  . . .

} item;

 

item buffer[BUFFER_SIZE];

int in = 0;

int out = 0;

 

Producer:

 

while (true) { 

       while ((( (in + 1) % BUFFER_SIZE)  == out)

         ;   /* do nothing -- no free buffers */

       /* Produce an item */

        buffer[in] = item;

        in = (in + 1) % BUFFER_SIZE;

}

 

Consumer:

 

while (true) {

        while (in == out)

          ; /* do nothing -- nothing to consume */

         /* Consume an item */

         item = buffer[out];

         out = (out + 1) % BUFFER_SIZE;

   }

 

 

ü This solution is correct, but can only use BUFFER_SIZE - 1  elements

 

 

Interprocess Communication – Message Passing

·       IPC facility provides two operations:

ü send (message) – message size fixed or variable

ü receive (message)

 

·       If P and Q wish to communicate, they need to:

ü establish a communication link between them

ü exchange messages via send/receive

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

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

Synchronization

Message passing may be either blocking or non-blocking

·       Blocking is considered synchronous

ü Blocking send has the sender block until the message is received

ü Blocking receive has the receiver block until a message is available

 

·       Non-blocking is considered asynchronous

ü Non-blocking send has the sender send the message and continue

ü Non-blocking receive has the receiver receive a valid message or null

 

 

 


Shared Memory

·       Process first creates shared memory segment:

segment id = shmget (IPC_PRIVATE, size, S_IRUSR | S_IWUSR);

 

·       Process wanting access to that shared memory must attach to it:

sharedmemory = (char *) shmat (id, NULL, 0);

 

·       The process could write/read to/from the shared memory:

sprintf (sharedmemory, "Writing to shared memory");

 

printf("%s", sharedmemory);

 

·       When done a process can detach the shared memory from its address space:

shmdt (sharedmemory);

 

EXAMPLE:

shm-posix.c

int main()

{

        /* the identifier for the shared memory segment */

        int   segment_id;

        /* a pointer to the shared memory segment */

        char*   shared_memory;

        /* the size (in bytes) of the shared memory segment */

        const int  segment_size = 4096;

 

        /** allocate  a shared memory segment */

        segment_id = shmget(IPC_PRIVATE, segment_size, S_IRUSR | S_IWUSR);

        /** attach the shared memory segment */

        shared_memory = (char *) shmat(segment_id, NULL, 0);

       

        /** write a message to the shared memory segment   */

        sprintf(shared_memory, "Hi there!");

        /** now print out the string from shared memory */

        printf("%s\n", shared_memory);

 

        /** now detach the shared memory segment */

        shmdt(shared_memory);

        /** now remove the shared memory segment */

        shmctl(segment_id, IPC_RMID, NULL);

        return 0;

}

 

«   To execute:

 

% shm-posix

 

shm-fork-posix.c

 

int  main()

{

        pid_t           pid;

        /* the identifier for the shared memory segment */

        int             segment_id;

        /* a pointer to the shared memory segment */

        char           *shared_memory;

        /* the size (in bytes) of the shared memory segment */

        const int       segment_size = 4096;

 

        /** allocate  a shared memory segment */

        segment_id = shmget(IPC_PRIVATE, segment_size, S_IRUSR | S_IWUSR);

        /** attach the shared memory segment */

        shared_memory = (char *) shmat(segment_id, NULL, 0);

 

        /* fork another process */

 

       pid = fork();

 

       if (pid == 0) {         /* child process */

                /** write a message to the shared memory segment   */

                sprintf(shared_memory, "I love my parents");

 

       } else {                /* parent process */

                sleep(1);

                /** now print out the string from shared memory */

                printf("Parent Got: %s\n", shared_memory);

 

                /** now detach the shared memory segment */

                if (shmdt(shared_memory) == -1) {

                        fprintf(stderr, "Unable to detach\n");

                }

                /** now remove the shared memory segment */

                shmctl(segment_id, IPC_RMID, NULL);

                return 0;

       }

}

 

«   To execute:

 

% shmfork-posix

 


Client-Server Communication

Sockets

·       A socket is defined as an endpoint for communication

·       Is bind  to of IP address (e.g., 128.82.4.98)  and port (e.g., 10123).

·       Communication is between a pair of sockets

EXAMPLE:

DateServer.java

public class DateServer

{

    public static void main(String[] args)  {

         try {

             ServerSocket sock = new ServerSocket(10123);

             // now listen for connections

             while (true) {

                 Socket client = sock.accept();                 

                 PrintWriter pout = new PrintWriter(client.getOutputStream(), true);

 

                 // write the Date to the socket

                 pout.println(new java.util.Date().toString());

 

                 // close the socket and resume listening for more connections

                 client.close();

             }

         }

         catch (IOException ioe) {

                 System.err.println(ioe);

         }

    }

}

DateClient.java

 

public class DateClient

{

    public static void main(String[] args)  {

         try {

             // this could be changed to an IP name or address other than the localhost

             Socket sock = new Socket("127.0.0.1",10123);

             InputStream in = sock.getInputStream();

             BufferedReader bin = new BufferedReader(new InputStreamReader(in));

             String line;

             while( (line = bin.readLine()) != null)

                 System.out.println(line);         

             sock.close();

         }

         catch (IOException ioe) {

                 System.err.println(ioe);

         }

}

 

 

«   To execute:

 

% java   DateServer

 

    In another window at the same host:

 

% java   DateClient

 

DateServer.c

int main(void)

{

        int             len, listenfd, connfd;

        struct sockaddr_in servaddr, cliaddr;

        char            buff[512];

        time_t          ticks;

 

        listenfd = socket (AF_INET, SOCK_STREAM, 0);

 

        bzero(&servaddr, sizeof(servaddr));

        servaddr.sin_family = AF_INET;

        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

        servaddr.sin_port = htons(10123);

 

        bind (listenfd, (SA *) & servaddr, sizeof(servaddr));

 

        listen(listenfd, 0);

 

        for (;;) {

                len = sizeof(cliaddr);

                connfd = accept (listenfd, (SA *) & cliaddr, &len);

 

                ticks = time(NULL);

                snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));

                write (connfd, buff, strlen(buff));

                close (connfd);

        }

}

 

 

DateClient.c

 

int main(int argc, char **argv)

{

        int             sockfd, n;

        char            recvline[512];

        struct sockaddr_in servaddr;

        struct hostent *hp, *gethostbyname();

 

        sockfd = socket (AF_INET, SOCK_STREAM, 0);

 

        bzero(&servaddr, sizeof(servaddr));

        servaddr.sin_family = AF_INET;

 

        hp = gethostbyname( “localhost” );

        bcopy ( hp->h_addr, &(servaddr.sin_addr.s_addr), hp->h_length);

        servaddr.sin_port = htons(10123);

 

        if (connect (sockfd, (SA *) & servaddr, sizeof(servaddr)) < 0) {

                perror("connect error");

                exit(-1);

        }

        read (sockfd, recvline, 512);

        printf("%s", recvline);

        exit(0);

}

 

«   To execute:

 

% DateServer

 

    In another window at the same host:

 

% DateClient

 


Pipes

·       Ordinary Pipes allow communication in standard producer-consumer style

·       Producer writes to one end (the write-end of the pipe)

·       Consumer reads from the other end (the read-end of the pipe)

·       Ordinary pipes are therefore unidirectional

·       Require parent-child relationship between communicating processes

Description: Description: Description: Description: Description: Picture 2.png

EXAMPLE:

unix_pipe.c

#define BUFFER_SIZE 25

#define READ_END        0

#define WRITE_END       1

 

int main(void)

{

        char write_msg[BUFFER_SIZE] = "Greetings";

        char read_msg[BUFFER_SIZE];

        pid_t pid;

        int fd[2];

 

        /** create the pipe */

        if (pipe(fd) == -1) {

                fprintf(stderr,"Pipe failed");

                return 1;

        }

        /** now fork a child process */

        pid = fork();

        if (pid < 0) {

                fprintf(stderr, "Fork failed");

                return 1;

        }

        if (pid > 0) {  /* parent process */

                /* close the unused end of the pipe */

                close(fd[READ_END]);

                /* write to the pipe */

                write(fd[WRITE_END], write_msg, strlen(write_msg)+1);

                /* close the write end of the pipe */

                close(fd[WRITE_END]);

        }

        else { /* child process */

                /* close the unused end of the pipe */

                close(fd[WRITE_END]);

                /* read from the pipe */

                read(fd[READ_END], read_msg, BUFFER_SIZE);

                printf("child read %s\n",read_msg);

                /* close the write end of the pipe */

                close(fd[READ_END]);

        }

        return 0;

}

 

«   To execute:

 

% unix_pipe

 


Shared Files

 

File Sharing between processes

Description: Description: Description: Description: fileSharing

EXAMPLES:

sharedFile1.c

int
main(int argc, char *argv[])
{
    int             n;
    int             i;
    int             sfd;
    pid_t           pid;
    char            buf[1024];

    if ((sfd = open("TempFile", O_RDWR | O_TRUNC | O_CREAT, 0600)) < 0) {
         perror("TempFile");
         exit(1);
    }
    if ((pid = fork()) < 0) {
         perror("fork");
        exit(1);
    }
    if (pid == 0) {
         sleep(1);
         lseek(sfd, 0, SEEK_SET);
         n = read(sfd, buf, sizeof(buf));
         write(1, buf, n);
         exit(0);
    } else {
         write(sfd, "Hi\n", 3);
         sleep(2);
         exit(0);
    }
}

«   To execute:

 

% sharedFile1

 

sharedFile2.c

int
main(int argc, char *argv[])
{
    int             n;
    int             sfd;
    int             sfd2;
    pid_t           pid;
    char            buf[1024];
    if ((pid = fork()) < 0) {
         perror("fork");
         exit(1);
    }
    if (pid == 0) { /* child */
         sleep(1);
         if ((sfd2 = open("TempFile", O_RDWR)) < 0) {
             perror("TempFile");
             exit(1);
         }
         n = read(sfd2, buf, sizeof(buf));
         write(1, buf, n);
         exit(0);
    } else { /* parent */
         if ((sfd = open("TempFile", O_RDWR | O_TRUNC | O_CREAT, 0600)) < 0) {
             perror("TempFile");
             exit(1);
         }
         write(sfd, "Hi\n", 3);
         sleep(2);
         exit(0);
    }
}

«   To execute:

 

% sharedFile2

 

 

 


Single Client Echo Server

 

EchoServer.c

 

 

int
main(int argc, char* argv[])
{
    int             len, listenfd, connfd;
    struct sockaddr_in servaddr, cliaddr;
    char            buff[512];
    int             nread;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(atoi(argv[1]));

    bind(listenfd, (SA *) & servaddr, sizeof(servaddr));

    listen(listenfd, 0);

    len = sizeof(cliaddr);
    connfd = accept(listenfd, (SA *) & cliaddr, &len);


    EchoToClient(connfd);
}

void
EchoToClient(int sockfd)
{

    int             nread;
    char            buffer[512];
    for (;;) {
         nread = read(sockfd, buffer, 512);
         if (nread == 0)
             break;
         write(sockfd, buffer, nread);
    }
}

 

EchoClient.c

 

 

int
main(int argc, char **argv)
{
    int             sockfd;
    struct sockaddr_in servaddr;
    struct hostent *hp, *gethostbyname();
    char            buffer[512];
    int             nread;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    hp = gethostbyname(argv[1]);
    bcopy(hp->h_addr, &(servaddr.sin_addr.s_addr), hp->h_length);
    servaddr.sin_port = htons(atoi(argv[2]));

    if (connect(sockfd, (SA *) & servaddr, sizeof(servaddr)) < 0) {
         perror("connect error");
         exit(-1);
    }
    for (;;) {
         nread = read(0, buffer, 512);
         if (nread == 0)
             exit(0);
         write(sockfd, buffer, nread);


         nread = read(sockfd, buffer, 512);
         write(1, buffer, nread);
    }
}

 

«   To execute:

 

       vega % EchoServer   10123

 

    In another window for the same host (vega)

 

% EchoClient    localhost     10123

   OR

       antares % EchoClient    vega     10123

 

 

Multi Client Echo Server

 

EchoServerFork.c

 

 

int
main(int argc, char *argv[])
{
    int             len, listenfd, connfd;
    struct sockaddr_in servaddr, cliaddr;
    char            buff[512];
    int             nread;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(atoi[argv[1]));

    bind(listenfd, (SA *) & servaddr, sizeof(servaddr));

    listen(listenfd, 0);

    for (;;) {
         len = sizeof(cliaddr);
         connfd = accept(listenfd, (SA *) & cliaddr, &len);
         if (fork() == 0)
             EchoToClient(connfd);
    }
}

void
EchoToClient(int sockfd)
{
    int             nread;
    char            buffer[512];
    for (;;) {
         nread = read(sockfd, buffer, 512);
         if (nread == 0)
             exit(0);
         write(sockfd, buffer, nread);
    }
}

 

EchoClientFork.c 

 

 

int
main(int argc, char **argv)
{
    int             sockfd;
    int             pid;
    struct sockaddr_in servaddr;
    struct hostent *hp, *gethostbyname();

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    hp = gethostbyname(argv[1]);
    bcopy(hp->h_addr, &(servaddr.sin_addr.s_addr), hp->h_length);
    servaddr.sin_port = htons(atoi(argv[2]));

    if (connect(sockfd, (SA *) & servaddr, sizeof(servaddr)) < 0) {
         perror("connect error");
         exit(-1);
    }

     pid = fork();
    if (pid == 0) {
         ReadFromKeyBoard(sockfd);
         kill(getppid(), 9);
    } else {
         ReadFromSocket(sockfd);
         kill(pid, 9);
    }
}

void
ReadFromKeyBoard(int sockfd)
{
    int             nread;
    char            buffer[512];
    for (;;) {
         nread = read(0, buffer, 512);
         if (nread == 0)
             break;
         write(sockfd, buffer, nread);
    }
}

void
ReadFromSocket(int sockfd)
{
    int             nread;
    char            buffer[512];
    for (;;) {
        nread = read(sockfd, buffer, 512);
         if (nread == 0)
             break;
         write(1, buffer, nread);
    }
}

 

«   To execute:

 

vega % EchoServerFork   10123

 

    In another window for the same host (vega)

 

% EchoClientFork    localhost     10123

 

    In another window for the another host (antares)

 

antares % EchoClientFork    vega     10123

 

Repeat for any number of other windows.

 

 

 


ęEcho Client Simple Version: EchoClientForkShort.c

                         .......

                         .......

 

     pid = fork();

     if (pid == 0) {

          ReadFrom(0, sockfd);

          kill(getppid(), 9);

     } else {

          ReadFrom(sockfd, 1);

          kill(pid, 9);

     }

}

 

void ReadFrom(int fd1, int fd2)

{

 

     int             nread;

     char            buffer[512];

     for (;;) {

          nread = read(fd1, buffer, 512);

          if (nread == 0)

                break;

          write(fd2, buffer, nread);

     }

 

}

 

ęEcho Client Optimal Version (remember  Kernighan’s Law  for Debugging! ):

         Note that writing to 0 is the same as writing to 1!

 

EchoClientForkOptimum.c

        
        ........
        ........
 
      dup2(sockfd, 1);
      close(sockfd);
      pid = fork();
      if (pid == 0) {
           ReadFrom(0);
           kill(getppid(), 9);
      } else {
           ReadFrom(1);
           kill(pid, 9);
      }
}
 
 
void ReadFrom(int fd)
{
 
      int             nread;
      char            buffer[512];
      for (;;) {
           nread = read(fd, buffer, 512);
           if (nread == 0)
                 break;
           write((fd + 1) % 2, buffer, nread);
      }
}