
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:
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:
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
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:
% shm-fork-posix
Shared-NonShared Example:
int
main()
{
int segment_id
= shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR);
int *sharedVar
= (int *) shmat(segment_id, NULL, 0);
int *nonsharedVar
= (int *) malloc(sizeof(int));
sharedVar[0] = 0;
nonsharedVar[0] = 0;
if (fork() ==
0) {
sharedVar[0]=12345;
nonsharedVar[0]=6789;
printf("\nChild : shared %d, nonshared %d\n", sharedVar[0],
nonsharedVar[0]);
exit(0);
}
wait(NULL);
printf("Parent : shared %d, nonshared
%d\n\n", sharedVar[0], nonsharedVar[0]);
}
« To execute:
% shmfork
Child : shared 12345, nonshared 6789
Parent :
shared 12345, nonshared 0
![]()
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:
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);
}
}
}
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
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);
}
}
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

EXAMPLES:
#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
main()
{
char buf[10];
int
pfd[2];
pipe(pfd);
int
n;
if (fork() == 0) {
write(pfd[1],
"child\n", 6);
n=read(pfd[0],
buf, 10);
write(1, buf, n);
exit(0);
}
n=read(pfd[0],
buf, 10);
write(1, buf, n);
write(pfd[1],
"parent\n", 7);
wait(NULL);
}
« To execute:
% pipefork
child
parent
![]()
Shared Files
File Sharing between processes
EXAMPLES:
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
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
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);
}
}
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:
procyon % EchoServer 10123
In another
window for the same host
% EchoClient localhost
10123
OR
antares
% EchoClient
procyon 10123
Multi Client Echo Server
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);
}
}
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:
antares % EchoServerFork 10123
In another window for the same
host (vega)
% EchoClientFork localhost 10123
In another window for the another host (antares)
antares % EchoClientFork antares
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!
........ ........ 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); }}