As a
process executes, it changes state
§ new: The process is
being created
§ ready: The process is
waiting to be assigned to a processor
§ running:
Instructions are being executed
§ waiting:
The process is waiting for some event to occur
§ 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 an overhead; the system does no useful work while switching
vProcess
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, pid2;
pid = fork();
if
(pid == 0) { // child process
printf(“%d
%d”, getpid(), getppid());
execlp("/bin/ls", "ls", NULL);
}
else
{ // parent process
pid2=wait (NULL);
printf ("%d %d %d",
pid2, getpid(), getppid());
exit(0);
}
}
« To execute:
%
newproc-posix
EXAMPLE:
#!
/usr/bin/env python
import sys
import os
childpid = os.fork()
if childpid == 0:
print("I am child")
os.execlp("/bin/date","date");
os.exit(0)
else:
os.wait()
print("I am the parent of:
", childpid)
« To execute:
%
newproc.py
v 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
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
vShared
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);
EXAMPLES:
int main()
{
pid_t pid;
int segment_id;
char *shared_memory;
const int segment_size =
4096;
segment_id = shmget(IPC_PRIVATE, segment_size,
S_IRUSR | S_IWUSR);
shared_memory = (char *) shmat(segment_id,
NULL, 0);
pid = fork();
if (pid == 0) {
/* child process */
sprintf(shared_memory, "I love my parents");
}
else { /* parent
process */
sleep(1);
printf("Parent Got: %s\n", shared_memory);
if (shmdt(shared_memory)
== -1) {
fprintf(stderr, "Unable to
detach\n");
}
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]=getpid();
nonsharedVar[0]=getpid();
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
vClient-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., 10117).
· Communication is between a pair
of sockets
EXAMPLE:
public class
DateServer
{
public static void main(String[] args)
{
try {
ServerSocket sock = new
ServerSocket(10117);
// 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",10117);
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(10117);
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(10117);
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
DateServer.py
#!
/usr/bin/env python
import socket
import sys
import os
import datetime
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = ''
port = 10117
s.bind((host,
port))
s.listen(1)
while (1):
conn, addr = s.accept()
print 'client is at', addr
#today = datetime.date.today()
date= datetime.datetime.now().strftime("%A %B %d %H:%M:%S EST %Y \n")
conn.send(date)
conn.close()
#! /usr/bin/env python
import socket
import sys
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "localhost"
port = 10117
s.connect((host,
port))
date = s.recv(1000000)
print (date)
s.close()
« To execute:
%
DateServer.py
In another window at the same
host:
% DateClient.py
Mix & Match:
You may
use any c/java/python server talk to any c/java/python client.
Also Try:
% telnet
127.0.0.1 10117
With all 3
servers.
i.e.,
there are 4x3 = 12 possible combinations.
vPipes
·
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 */
pipe(fd)
/** now fork
a child process */
pid = fork();
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]);
}
}
« 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
#!/usr/bin/python
import os, sys
# file descriptors r, w for reading and writing
r, w = os.pipe()
processid = os.fork()
if processid: #parent
os.close(w)
r = os.fdopen(r)
str = r.read()
print "Parent Got: ", str
sys.exit(0)
else:
os.close(r)
w = os.fdopen(w,
'w')
w.write("How
are you my dear Parent.." )
w.close()
sys.exit(0)
« To execute:
% pipe.py
vShared Files
File Sharing
between processes
EXAMPLES:
sharedFile1.c ( single open)
int
main(int argc, char *argv[])
{
int n;
int i;
int sfd;
pid_t pid;
char buf[1024];
sfd =
open("TempFile", O_RDWR | O_TRUNC |
O_CREAT, 0600);
pid = fork;
if (pid == 0) {
sleep(1);
lseek(sfd,
0, SEEK_SET);
n = read(sfd, buf, sizeof(buf));
write(1, buf,
n);
exit(0);
} else { /* Parent */
write(sfd,
"Hi\n", 3);
sleep(2);
exit(0);
}
}
« To execute:
%
sharedFile1
sharedFile2.c (two opens)
int
main(int argc, char *argv[])
{
int n;
int sfd;
int sfd2;
pid_t pid;
char buf[1024];
pid = fork();
if (pid == 0) { /* child */
sleep(1);
sfd2 = open("TempFile", O_RDWR;
n = read(sfd2,
buf, sizeof(buf));
write(1, buf,
n);
exit(0);
} else { /* parent */
sfd = open("TempFile",
O_RDWR | O_TRUNC | O_CREAT, 0600) ;
write(sfd, "Hi\n", 3);
sleep(2);
exit(0);
}
}
« To execute:
%
sharedFile2
v Echo Server (Serving single client)
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:
sirius %
EchoServer 10123
In another window for the same
host sirius
sirius % EchoClient
localhost 10123
OR login to another
host, e.g., artia
atria % EchoClient sirius 10123
vConcurrency using fork
Echo Server (serving multiple clients simultaniusly)
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) { /* child */
ReadFromKeyBoard(sockfd);
kill(getppid(),
9); /* kill parent */
} else { /* parent */
ReadFromSocket(sockfd);
kill(pid,
9); /* kill child */
}
}
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:
cirius %
EchoServerFork 10123
In another window for the same host (vega)
%
EchoClientFork localhost 10123
In another window for the another
host (antares)
atria %
EchoClientFork cirius
10123
Repeat
for any number of other windows.
v
Be Clever!
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);
}
}
v
Be Smart!
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);
}
}
v Python Echo Server &
Client
#! /usr/bin/env python
import socket
import sys
import os
import datetime
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
host = ''
port = int(sys.argv[1])
s.bind((host, port))
s.listen(1)
while (1):
conn, addr = s.accept()
print 'client is at', addr
childpid = os.fork()
if childpid ==
0:
print("child,
serving echo client")
while (1):
data
= conn.recv(1000000)
if not data: # if end of data, leave loop
print("child,
echo client is done")
conn.close()
exit(0)
conn.send(data)
else:
print("I
am the parent of: ", childpid)
conn.close()
#! /usr/bin/env python
import socket
import sys
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
host = sys.argv[1] # server address
port = int(sys.argv[2]) #
server port
s.connect((host, port))
while(1):
print 'type a line (type CTRL-D when
done)'
line = sys.stdin.readline() # keyboard input, ctrl-d to end
if not line: # if end of data, leave loop
break
s.send(line)
data = s.recv(1000000) # read up to 1000000 bytes
print 'received', len(data),
'bytes: ', data
s.close()
« To execute:
sirius % EchoServerFork.py 10123
In another
window for the same host
%
EchoClient.py localhost 10123
OR
atria
% EchoClient.py sirius 10123
Basic Signal Handling:
kill (pid, sig)
Send process pid signal sig
(To list all available signals type: % kill -l )
It is called kill since the default action is to
kill the process.
signal (sig, handler)
To catch & handle signal.
When signal sig occurs,
call function handler
pause ()
To wait for
the arrival of any signal
Example: signal1.c
main ()
{
signal(SIGUSR1, handler);
signal(SIGUSR2,
handler);
for (;;) pause();
}
handler(int sig)
{
/* Print received signal */
psignal(sig, "Received
signal");
}
To execute:
% signal1
% kill -USR1 12345 //use ps to find pid of signal1 e.g., 12345
Recived signal: User Signal 1
To list signals use:
% kill -l
HUP INT QUIT ILL TRAP ABRT
BUS FPE KILL USR1 SEGV
USR2 PIPE ALRM TERM
STKFLT CHLD CONT STOP TSTP
TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL
PWR SYS RTMIN RTMIN+1
RTMIN+2 RTMIN+3 RTMAX-3 RTMAX-2 RTMAX-1 RTMAX
Then
you can use:
% kill -10 12345 //signal #10 is USR1
Recived signal: User Signal 2
% kill -KILL 12345 //signal #9 is KILL
Killed
A process can
NOT catch or ignore (using SIG_IGN) the KILL signal.
Example: basic-signal.c
main(int argc,
char *argv[])
{
int i;
signal(SIGINT, SIGhandler);
printf("\nParent
Process, PID: %d\n", getpid());
for(;;){
printf("HI %c\n", (i++) %26
+'A');
sleep(1);
}
}
void SIGhandler(int sig)
{
signal(sig,
SIGhandler);
psignal(sig, "\nReceived
SIGhandler1 signal");
}
To execute:
% basic-signal
Type: CTRL-C
OR
Type: CTRL-\
to exit
Example: fork-signal.c
main(int argc, char *argv[])
{
signal(SIGINT,
SIGhandler);
if (fork() == 0){
printf("Child
Process1, PID: %d", getpid());
for (;;) pause();
}
if (fork()
== 0){
signal(SIGINT, SIG_IGN);
printf("Child
Process2, PID: %d", getpid());
for (;;) pause();
}
printf("Parent Process, PID: %d", getpid());
for (;;) pause();
}
void SIGhandler(int sig)
{
printf("Process, PID: %d", getpid());
signal(sig, SIGhandler);
psignal(sig, "Received SIGhandler
signal");
}
To execute:
% fork-signal
Type: CTRL-C
OR
Type: CTRL-\
to exit
Python Signal Example: signal.py
#! /usr/bin/python
import os
import signal
import time
import sys
def INThandle (signum,
frame ):
print ("Got SIGINT, PID: ", os.getpid())
print( "SIGINT number:", signum)
pass
signal.signal( signal.SIGINT,
INThandle
)
childpid = os.fork()
if childpid == 0:
print("I am child, my PID: ", os.getpid())
signal.pause()
print("Child: got SIGINT
signal")
else:
print("I am the parent, my PID: ", os.getpid())
print("My child PID: ", childpid)
signal.pause()
print("Parent: got SIGINT
signal")
To execute:
% signal.py
Type: CTRL-C
OR
Type: CTRL-\ to exit