1Computer Science 213© 2006 Donald Acton
Layering Yet Again!Layering Yet Again!
Application programs
Operating system
Hardware
General Layering
Structure
Application
Transport
Network
Link
Network
Layering
Application
Unix I/O
File System
Disk Drive
File System
Layering
2Computer Science 213© 2006 Donald Acton
On to protocolsOn to protocols
• We just finished file systems and explored what happened from the disk to the application
• A layered approach was used to organize things
• We are going to start at the application layer and explore computer protocols
3Computer Science 213© 2006 Donald Acton
Communication Between Processes
Communication Between Processes
• When talking about shells the concept of pipes was introduced
grep "ok:" inputfile | sort | less
• This is really just one process sending data to another. It is a form of Interprocess Communication (IPC).
4Computer Science 213© 2006 Donald Acton
Local IPCLocal IPC
Process1
Process2
Pipe
5Computer Science 213© 2006 Donald Acton
Remote IPCRemote IPC
Process1
Process2
Pipe
6Computer Science 213© 2006 Donald Acton
What Problems Does this Present?
What Problems Does this Present?
Process1
Process2
7Computer Science 213© 2006 Donald Acton
Problem SummaryProblem Summary
• Initiator needs– something to write
to– to identify the
recipient– to define the
“language” of the data exchange
– a mechanism to make the call
• Receiver needs– something to read
from– to define the
“language” of the data exchange
– a mechanism to accept a call
– “caller ID” (sort of)
8Computer Science 213© 2006 Donald Acton
IPC StagesIPC Stages
A communication between processes can be decomposed into 3 stages:
1. Establishing the connection between the callee and caller
2. Transferring of data3. Disconnecting (closing) the connection
The collection of calls involved in the above phases is the Socket API
9Computer Science 213© 2006 Donald Acton
Identifying the CalleeIdentifying the Callee
• Must identify the machine being called– DNS Name (www.cs.ubc.ca) is the human
readable form– Gets translated to an IP address
(142.103.6.5, 127.0.0.1)
• Must identify the recipient on the machine– Port number – Port 80 (www-http), 194 (irc)
10Computer Science 213© 2006 Donald Acton
Internet ConnectionsInternet Connections
Connection socket pair(128.2.194.242 :51213, 208.216.181.15:80)
Receiver(port 80)
Sender
Sender socket address128.2.194.242:51213
Receiver socket address208.216.181.15:80
Sender host address128.2.194.242
Receiver host address208.216.181.15
Adapted from: Computer Systems: A Programmer’s Perspective
11Computer Science 213© 2006 Donald Acton
Establishing the Connection (1)Establishing the Connection (1)
• Caller– Creating the
“endpoint”
int fd;
fd = socket(PF_INET,SOCK_STREAM,0);
12Computer Science 213© 2006 Donald Acton
Establishing the Connection (2)Establishing the Connection (2)
• Caller– Getting ready to make the call
struct sockaddr_in remoteAddr;unsigned long remoteIP = htonl(0xAB112090);
memset(&remoteAddr, 0, sizeof(remoteAddr));remoteAddr.sin_family = PF_INET;memcpy(&remoteAddr.sin_addr.s_addr, &remoteIP, sizeof(remoteIP));remoteAddr.sin_port = htons(7891);
13Computer Science 213© 2006 Donald Acton
Establishing the Connection (3)Establishing the Connection (3)
• Caller– Making the actual call
connect(fd, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
• Ready to transmit/receive data when the call returns
14Computer Science 213© 2006 Donald Acton
CalleeCallee
Caller1. Create a socket
2. Connect to
callee3. Transfer data4. Close
connection
Callee1. Create socket2. Specify contact
point (binding)3. Listen for calls4. Accept call5. Transfer data6. Close connection
15Computer Science 213© 2006 Donald Acton
Establishing the Connection (1)Establishing the Connection (1)
Callee – struct sockaddr_in callerAddr; memset(&callerAddr,0,sizeof(callerAddr)); callerAddr.sin_family = PF_INET; callerAddr.sin_addr.s_addr =
htonl(INADDR_ANY);
callerAddr.sin_port = htons(7891); bind(fd, (struct sockaddr *) &callerAddr, sizeof(callerAddr))
16Computer Science 213© 2006 Donald Acton
Purpose of BindPurpose of Bind
• Consider a machine with multiple network cards – Wireless and wired– Server on more than one network
17Computer Science 213© 2006 Donald Acton
Establishing the Connection (2)Establishing the Connection (2)
• Callee – must tell the system it is ready to listen for connectionslisten(fd, 4)– fd – file descriptor of socket to listen– 2nd argument is how many unanswered
calls to queue up (your call is important to us please stay on the line!)
18Computer Science 213© 2006 Donald Acton
Establishing the Connection (3)Establishing the Connection (3)
• Callee needs to actually accept the call
struct sockaddr_in caller;int cl_len = sizeof(caller);int callerFD;callerFD = accept(fd, (struct sockaddr *)&caller, &cl_len);
19Computer Science 213© 2006 Donald Acton
Setting up a ConnectionSetting up a Connection
listenfd(3)
Caller
1. Callee blocks in accept, waiting for connection request on listening descriptor listenfd.
clientfd
Callee
listenfd(3)
Caller
clientfd
Callee 2. Caller makes connection request bycalling and blocking in connect.
listenfd(3)
Caller
clientfd
Callee
3. Callee returns connfd from accept.Caller returns from connect. Connection is now established between clientfd
and connfd.
connectionrequest
connfd(4)
Adapted from: Computer Systems: A Programmer’s Perspective
20Computer Science 213© 2006 Donald Acton
Who Called?Who Called?
• Callee can determine caller by examining 2nd parameter
unsigned long callerIP = ntohl(caller.sin_addr.s_addr);unsigned short = ntohs(caller.sin_port);
21Computer Science 213© 2006 Donald Acton
DisconnectingDisconnecting
• Either caller or callee can terminate a connection with the close() system call
close(callerFD);
22Computer Science 213© 2006 Donald Acton
Exchanging DataExchanging Data
• Once the connection is established caller and callee can both send and receive data– i.e. the connection is bi-directional– The data is not interpreted by the
sockets and it is just a series of bytes. – Calls to send and receive are:
•send()/write()•recv()/read()
23Computer Science 213© 2006 Donald Acton
The CallerThe Caller#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <time.h>int main(){ int fd; fd = socket(PF_INET, SOCK_STREAM,
0);
struct sockaddr_in remoteAddr; unsigned long remoteIP = htonl(0x7F000001); memset(&remoteAddr, 0,
sizeof(remoteAddr));
remoteAddr.sin_family = PF_INET; memcpy(&remoteAddr.sin_addr.s_addr, &remoteIP, sizeof(remoteIP)); remoteAddr.sin_port = htons(7891);
if (connect(fd, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr)) < 0) {
perror("Connection failed"); } else { char *msg = "Hi there\n"; time_t ltime; char buff[256]; time(<ime); write(fd, <ime, sizeof(ltime)); write(fd, msg, 10); int amt; amt = read(fd, buff, 256); while( amt > 0) { printf("Buffer %s", buff); amt = read(fd, buff, 256); } }}
24Computer Science 213© 2006 Donald Acton
Caller´ (1)Caller´ (1)
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <time.h>int main(){ int fd; fd = socket(PF_INET, SOCK_STREAM, 0);
25Computer Science 213© 2006 Donald Acton
Caller´ (2)Caller´ (2)
struct sockaddr_in remoteAddr;
unsigned long remoteIP = htonl(0x7F000001);
memset(&remoteAddr, 0, sizeof(remoteAddr));
26Computer Science 213© 2006 Donald Acton
Caller´ (3)Caller´ (3)
remoteAddr.sin_family = PF_INET;
memcpy(&remoteAddr.sin_addr.s_addr, &remoteIP, sizeof(remoteIP));
remoteAddr.sin_port = htons(7891);
if (connect(fd, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr)) < 0) {
27Computer Science 213© 2006 Donald Acton
Caller´ (4)Caller´ (4)
perror("Connection failed"); } else { char *msg = "Hi there\n"; time_t ltime; char buff[256]; time(<ime); write(fd, <ime, sizeof(ltime)); write(fd, msg, 10); int amt;
28Computer Science 213© 2006 Donald Acton
Caller´Caller´
amt = read(fd, buff, 256);
while( amt > 0) {
printf("Buffer %s", buff);
amt = read(fd, buff, 256);
}
}
}
29Computer Science 213© 2006 Donald Acton
CalleeCallee#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <time.h>int main(){ int fd; fd = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in callerAddr; memset(&callerAddr, 0, sizeof(callerAddr)); callerAddr.sin_family = PF_INET; callerAddr.sin_addr.s_addr = htonl(INADDR_ANY); callerAddr.sin_port = htons(7891); bind(fd, (struct sockaddr *) &callerAddr,
sizeof(callerAddr)); listen(fd, 4); struct sockaddr_in caller;
while(1) { int cl_len = sizeof(caller); int callerFD; callerFD = accept(fd,
(struct sockaddr *)&caller, &cl_len);
char buff[256]; int amt; time_t rtime; recv(callerFD, &rtime, sizeof(time_t), 0); amt = recv(callerFD, buff, 256, 0); printf("%s", buff); struct hostent *hp; hp = gethostbyaddr((char *)
&caller.sin_addr.s_addr, sizeof(long), PF_INET);
amt = snprintf(buff,256, "Connection from %s (%x) %x at %s",
hp->h_name, ntohl(caller.sin_addr.s_addr), (long) ntohs(caller.sin_port), ctime(&rtime));
send(callerFD, buff, amt, 0); sleep(10); send(callerFD, "Bye\n", 5, 0); close(callerFD); }}
30Computer Science 213© 2006 Donald Acton
Callee (1)Callee (1)
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <time.h>int main(){ int fd;
fd = socket(PF_INET, SOCK_STREAM, 0);
31Computer Science 213© 2006 Donald Acton
Callee (2)Callee (2)
struct sockaddr_in callerAddr;
memset(&callerAddr, 0, sizeof(callerAddr));
callerAddr.sin_family = PF_INET;
callerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
callerAddr.sin_port = htons(7891);
32Computer Science 213© 2006 Donald Acton
Callee (3)Callee (3) bind(fd, (struct sockaddr *) &callerAddr, sizeof(callerAddr));
listen(fd, 4);
struct sockaddr_in caller;
while(1) {
int cl_len = sizeof(caller);
int callerFD
callerFD = accept(fd, (struct sockaddr *)&caller, &cl_len);
33Computer Science 213© 2006 Donald Acton
Callee (4)Callee (4)
char buff[256];
int amt;
time_t rtime;
recv(callerFD, &rtime, sizeof(time_t), 0);
amt = recv(callerFD, buff, 256, 0);
printf("%s", buff);
34Computer Science 213© 2006 Donald Acton
Callee (5) Callee (5)
struct hostent *hp; hp = gethostbyaddr((char *) &caller.sin_addr.s_addr, sizeof(long),PF_INET);
amt = snprintf(buff,256, "Connection from %s (%x) %x at %s",
hp->h_name, ntohl(caller.sin_addr.s_addr), (long) ntohs(caller.sin_port), ctime(&rtime));
35Computer Science 213© 2006 Donald Acton
Callee (6)Callee (6)
send(callerFD, buff, amt, 0);
sleep(10);
send(callerFD, "Bye\n", 5,0);
close(callerFD);
}
}
36Computer Science 213© 2006 Donald Acton
Typical Call ProgressTypical Call ProgressCaller Callee
socket socket
bind
listen
accept
close
read
writeread
connect
write
read
Connectionrequest
EOF
Await connectionrequest fromnext caller
Adapted from: Computer Systems: A Programmer’s Perspective
37Computer Science 213© 2006 Donald Acton
BSD Socket API SummaryBSD Socket API Summary• socket() – creates the socket• connect() – initiate a connection• bind() – indicates the IP address to use• listen() – marks the socket to receive
connections• read()/recv() – reads data• write()/send() - writes data• close() – shuts down the connection
38Computer Science 213© 2006 Donald Acton
Other Useful FunctionsOther Useful Functions
• inet_aton() – string to network address
• inet_ntoa() – network address to string
• gethostbyname() gethostbyaddr() given a host name or address look it up
39Computer Science 213© 2006 Donald Acton
Client Server ModelClient Server Model
• When designing a network based application how can we decide what goes where?
• One approach is to divide the functionality into client and server components
40Computer Science 213© 2006 Donald Acton
Client/ServerClient/Server
• Client – is a process that is requesting some sort of service
• Server – is a process that supplies a service
• A particular process can be both a client and server
41Computer Science 213© 2006 Donald Acton
Changing RolesChanging Roles
Database
HTTP Server
42Computer Science 213© 2006 Donald Acton
Request/ResponseRequest/Response
Clientprocess
Serverprocess
1. Client sends request
2. Server processes
request
3. Server sends response4. Client processesresponse
Resource
Adapted from: Computer Systems: A Programmer’s Perspective
43Computer Science 213© 2006 Donald Acton
The Chat ProblemThe Chat Problem
• Consider the following application scenario– Two network connected computers – Want to implement “chat”– When each user types their typing
appears on the other screen– User’s do not have to take turns and can
type at any time
44Computer Science 213© 2006 Donald Acton
The Application’s TaskThe Application’s Task• Each application has two things to do
it must:– Read input from the keyboard and send
it to the remote machine– Read input from the remote machine
and write it to the screen
45Computer Science 213© 2006 Donald Acton
Start with what we knowStart with what we know
• Assume we have the network connection established
while(1) {
read from networkwrite to screenread from keyboardwrite to network
}
46Computer Science 213© 2006 Donald Acton
Do it with Fork!Do it with Fork!
if (fork()) { // parent
read from network
write to screen
} else { //child
read from keyboard
write to network
}
47Computer Science 213© 2006 Donald Acton
Fork()Fork()
Chat ChatSocket
Chat Chat
48Computer Science 213© 2006 Donald Acton
That was easy!That was easy!
• But…..– The overhead of forking the process is
high especially if the child is short lived– Exchanging information between the
child and parent is difficult– It is difficult for the parent to track the
children for resource management issues
49Computer Science 213© 2006 Donald Acton
HTTP Server ExampleHTTP Server Example
• Accepts connections• Client sends commands
– GET, POST, OPTIONS, HEAD, PUT, DELETE
• Commands are in plain text ASCII• Server parses the request and sends
back content• 99% of HTTP requests are GETs
50Computer Science 213© 2006 Donald Acton
Niave HTTP serverNiave HTTP server
while (1) {
accept connection
perform http request
close connection
}
51Computer Science 213© 2006 Donald Acton
Request TimelineRequest Timeline
52Computer Science 213© 2006 Donald Acton
HTTP Server – fork()HTTP Server – fork()while (1) {accept connection
if (fork() == 0) { perform http request processing} else {
if (too many workers) { wait for worker
}}
53Computer Science 213© 2006 Donald Acton
Observations about ServerObservations about Server
• We would like to control the number of processes created
• Each request is computationally light and has little state and is small
• Also, could we have a design that, if appropriate, doesn’t force the client to open a new connection for each request?
54Computer Science 213© 2006 Donald Acton
Worker PoolWorker Pool
• How about a model where there are a bunch of workers
• One worker checks for a connection to see if data arrives
• On data arrival worker services request
• New worker starts waiting
55Computer Science 213© 2006 Donald Acton
Worker Pool DemonstrationWorker Pool Demonstration
56Computer Science 213© 2006 Donald Acton
Process ShortcomingsProcess Shortcomings
• Switching between processes (i.e. scheduling) is slow
• Sharing large amounts of data through pipes or sockets is difficult
57Computer Science 213© 2006 Donald Acton
ThreadsThreads
• To get rid of some of the problems of processes we can use threads
• Threads– Are started by a process and stay within
that process– Execute independently of each other– Share the same memory space
58Computer Science 213© 2006 Donald Acton
Threads and ProcessesThreads and Processes
Computer
59Computer Science 213© 2006 Donald Acton
Thread StatesThread States
New
Ready
Blocked
DeadRunning
60Computer Science 213© 2006 Donald Acton
Thread APIThread API
• Defined by POSIX.1c• The API defines > 60 functions!!!• Java Thread class is much smaller
and many of the methods are informational
61Computer Science 213© 2006 Donald Acton
Most Useful Thread FunctionsMost Useful Thread Functions
• Creating a thread• Starting the thread• Waiting for a thread to terminate• Terminating a thread• To simplify the using of threads let’s
develop an encapsulation of the simplest thread functions
62Computer Science 213© 2006 Donald Acton
Encapsulation StrategyEncapsulation Strategy
Recall that an object is:–A collection of data that captures the state of the object
–A collection of methods that operate on the state
Is there some way to emulate this in a language like C?
63Computer Science 213© 2006 Donald Acton
Approach?Approach?
What C construct could be used to aggregate data?
structsWhat about methods?
functions
64Computer Science 213© 2006 Donald Acton
OrganizationOrganization
Java• new
C• A function that
allocates and initializes the struct and returns a pointer to the struct
struct Point { float x; float y; };
void *newPoint() {
struct Point *pt;
if (pt = malloc(sizeof(struct Point))) {
pt->x = pt->y = 0;
}
return pt;
}
65Computer Science 213© 2006 Donald Acton
Organization cont’dOrganization cont’d
Java• Method invocation
point.method()
C• Just call a function,
but make the first parameter be the “object”
void *pt;
pt = newPoint();
setPoint(pt, 3.4, 1.3);
66Computer Science 213© 2006 Donald Acton
Encapsulation ExampleEncapsulation Example
struct Point { float x; float y; };
void *newPoint() {
struct Point *pt;
if (pt = malloc(sizeof(struct Point))) {
pt->x = pt->y = 0;
}
return pt;
}
void setPoint(void * obj, float x, float y) {
struct Point *pt = obj;
pt->x = x;
pt->y = y;
}
main() {
void *pt;
pt = newPoint();
setPoint(pt, 3.4, 1.3);
….
}
67Computer Science 213© 2006 Donald Acton
Relationship Between Thread Encapsulation and pthread
Relationship Between Thread Encapsulation and pthread
pthread
A
pthread
B
pthread
C
Thread
A
Thread
B
Thread
C
68Computer Science 213© 2006 Donald Acton
Needed FunctionalityNeeded Functionality• Creation
– int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine, void*), void *arg);
• Cancellation – int pthread_cancel( pthread_t target_thread);
69Computer Science 213© 2006 Donald Acton
Functionality cont’dFunctionality cont’d
• Join– int pthread_join(pthread_t thread,
void **status);
• Detach– int pthread_detach( pthread_t thread);
71Computer Science 213© 2006 Donald Acton
Thread StructThread Struct
struct Thread {
void *(*entry_pt)(void*);
void *arg;
pthread_t id; // the thread ID
};int pthread_create(pthread_t *thread,
const pthread_attr_t *attr, void *(*start_routine, void*), void *arg);
72Computer Science 213© 2006 Donald Acton
Thread FunctionsThread Functions
void *createThread(void* (*func)(void*),
void *parm);
int runThread(void *vthread, pthread_attr_t *attr);
int cancelThread(void * vthread);
int joinThread(void * vthread, void **thread_return);
73Computer Science 213© 2006 Donald Acton
Thread Functions cont’dThread Functions cont’d
int detachThread(void *vthread);
pthread_t getThreadID( void *vthread);
void* getThreadArg( void *vthread);
78Computer Science 213© 2006 Donald Acton
createThreadcreateThread
void *createThread(void* (*func)(void*), void * parm) {
struct Thread *thread; thread = malloc(sizeof(struct Thread)); if (thread) { thread->entry_pt = func; thread->arg = parm; } return thread;}
79Computer Science 213© 2006 Donald Acton
runThreadrunThreadint runThread(void *vthread, pthread_attr_t *attr) { struct Thread *thread = vthread; if (vthread) { return pthread_create(&thread->id, attr,
thread->entry_pt, thread->arg ); } return -10;}
int cancelThread(void * vthread){ struct Thread *thread = vthread; return pthread_cancel(thread->id);}
80Computer Science 213© 2006 Donald Acton
joinThreadjoinThreadint joinThread(void * vthread, void **thread_return){ struct Thread *thread = vthread; return pthread_join(thread->id, thread_return);}
int detachThread(void *vthread) // reaps a thread{ struct Thread *thread = vthread; return pthread_detach(thread->id);}
81Computer Science 213© 2006 Donald Acton
AccessorsAccessorspthread_t getThreadID(void *vthread){ struct Thread *thread = vthread; return thread->id;}
void* getThreadArg(void * vthread){ struct Thread *thread = vthread; return thread->arg;}
85Computer Science 213© 2006 Donald Acton
Creating and Running a ThreadCreating and Running a Thread
void *sortAndPrint(void *array) { … }
void *t2;t2 = createThread(sortAndPrint, ar1);runThread(t2, NULL);detachThread(t2); // Only call after
// runcancelThread(t2);free(t2);
86Computer Science 213© 2006 Donald Acton
JoiningJoining
• Threads can only execute as long as their containing process exists
• The main() body of a program is a thread
• If any thread either directly or indirectly calls exit() or _exit() the process will be terminated
87Computer Science 213© 2006 Donald Acton
Joining cont’dJoining cont’d
• If all the process’s work is being done by threads started from main() then main must not return prematurely
• Any thread can wait for another thread with the pthread_join() call encapsulated by:
joinThread(t2, NULL);
88Computer Science 213© 2006 Donald Acton
Example Sorting and Printing
Example Sorting and Printing
• Have a function that takes as an argument an array of integers, sorts, and then prints them
• main() – Creates 3 arrays of integers– Creates 3 threads – Starts all 3 threads “simultaneously”
89Computer Science 213© 2006 Donald Acton
Sort and PrintSort and Printint cs213Compare(const void *a, const void *b) { return *(int *)a - *(int *)b;}
void *sortAndPrint(void *array) { int i; int *b; b = (int *) array; qsort(array, aSize, sizeof(int), cs213Compare); for (i=0; i<aSize; i++) { printf("%3d ", b[i]); fflush(stdout); } printf("\n"); return NULL;}
90Computer Science 213© 2006 Donald Acton
Sort and PrintSort and Print
int main(int argc, char * argv[]){ int array1[aSize]; int array2[aSize]; int array3[aSize]; int i; srandom(time(NULL)); for (i = 0; i < aSize; i++) { array1[i] = random() % (aSize * 10); array2[i] = random() % (aSize * 10); array3[i] = random() % (aSize * 10); printf("%3d %3d %3d\n", array1[i], array2[i],
array3[i]); }
91Computer Science 213© 2006 Donald Acton
Sort and PrintSort and Print printf("\n");
void *t1, *t2, *t3; t1 = createThread(sortAndPrint, array1); t2 = createThread(sortAndPrint, array2); t3 = createThread(sortAndPrint, array3);
runThread(t2, NULL); pthread_attr_t attr; pthread_attr_init(&attr); runThread(t3, &attr); runThread(t1, NULL);
joinThread(t1, NULL); joinThread(t2, NULL); joinThread(t3, NULL); return 0;}
92Computer Science 213© 2006 Donald Acton
Compare FunctionCompare Function
int cs213Compare(const void *a, const void *b) {
return *(int *)a - *(int *)b;
}
93Computer Science 213© 2006 Donald Acton
Sort and Print FunctionSort and Print Function
void *sortAndPrint(void *array) { int i; int *b; b = (int *) array; qsort(array, aSize, sizeof(int), cs213Compare); for (i=0; i<10; i++) { printf("%3d ", b[i]); fflush(stdout); } printf("\n"); }
94Computer Science 213© 2006 Donald Acton
Filling the arraysFilling the arrays
srandom(time(NULL));
for (i = 0; i < aSize; i++) {
array1[i] = random() % (aSize * 10);
array2[i] = random() % (aSize * 10);
array3[i] = random() % (aSize * 10);
printf("%3d %3d %3d\n", array1[i], array2[i], array3[i]);
}
95Computer Science 213© 2006 Donald Acton
Running the ThreadsRunning the Threadsvoid *t1, *t2, *t3;t1 = createThread(sortAndPrint, array1);t2 = createThread(sortAndPrint, array2);t3 = createThread(sortAndPrint, array3);
runThread(t2, NULL);pthread_attr_t attr; pthread_attr_init(&attr);runThread(t3, &attr); runThread(t1, NULL); joinThread(t1, NULL);joinThread(t2, NULL);joinThread(t3, NULL);
96Computer Science 213© 2006 Donald Acton
Output 1Output 1 53 14 27 2 31 85
30 11 67
50 7 39
29 16 79
3 99 90
40 26 32
29 82 64
15 61 73
75 38 23
This is the output from main of the unsorted numbers
97Computer Science 213© 2006 Donald Acton
Output 2Output 2
2 3 15 29 29 30 40 50 53 75 7 11 14 16 26 31 38 61 82 99
23 27 32 39 64 67 73 79 85 90
98Computer Science 213© 2006 Donald Acton
Output 3Output 3
2 3 15 29 7 61 … 53 75 99
23 27 32 39 64 67 73 79 85 90
2 3 15 29 7 … 99 50 53 32 75 39
64 67 73 79 85 90
99Computer Science 213© 2006 Donald Acton
What Happened?What Happened?
• Before one thread finished, its quantum expired and another thread was run
• The thread switched out hadn’t finished
• Exactly when the switch occurs is unpredictable; therefore the output is unpredictable
100Computer Science 213© 2006 Donald Acton
But why?But why?
• What is being shared?– The file descriptor attached to stdout, in
this example it is the screen (window)– Each time the thread is given a time
quantum it writes to stdout– The threads are taking turns writing to
stdout, hence the mixed output
101Computer Science 213© 2006 Donald Acton
Real life examplesReal life examples
• Can you think of some real life examples where there is some notion of sharing, how is it regulated?
102Computer Science 213© 2006 Donald Acton
Semaphores, the Computer Equivalent
Semaphores, the Computer Equivalent
• Developed by Edsger Dijkstra to solve synchronization problem in concurrent programming environments
• A special global variable, s, that can only be manipulated by the operations P(s) (proberen) and V(s) (verhogen)
• Works for both processes and threads
103Computer Science 213© 2006 Donald Acton
AtomicAtomic
Definition: A series of actions is said to be
atomic if the execution of the actions has the exact same result as if the actions had been performed sequentially without interruption.
104Computer Science 213© 2006 Donald Acton
Semaphore SemanticsSemaphore Semantics
• V(s) [ s = s + 1]– Operation is performed atomically
• P(s) [while (s == 0) {wait}; s = s – 1]– The test for 0 and decrement are done
atomically– If s is 0 then the process waits until the
value of s is modified by a V operation
105Computer Science 213© 2006 Donald Acton
Underlying Semaphore Implementation
Underlying Semaphore Implementation
We know– That an application can be interrupted
at any time– That the kernel can schedule a new
process to run– When executing in the kernel interrupts
are disabled therefore any series of instructions is atomic
106Computer Science 213© 2006 Donald Acton
Semaphore APISemaphore API
• Part of POSIX 1003.1b• Supplies semaphores in various
formats• Upon creation the semaphore values
is normally set to 0, although other values are allowed
• You will work with the supplied Semaphore class
107Computer Science 213© 2006 Donald Acton
Semaphore EncapsulationSemaphore Encapsulation
void P(sem_t *_sysSem);
void V(sem_t *_sysSem);
sem_t createSemaphore();void destroySemaphore(sem_t
**_sysSem);
108Computer Science 213© 2006 Donald Acton
createSemaphore()createSemaphore()
sem_t *createSemaphore(int count) { sem_t *_sysSem = malloc(sizeof(sem_t)); if (_sysSem) { memset( _sysSem, 0, sizeof( sem_t ) ); if (sem_init(_sysSem, 0, count) != 0) { // perror("Getting semaphore failed"); free(_sysSem); _sysSem = NULL; } } return _sysSem;}
109Computer Science 213© 2006 Donald Acton
destroySemaphore()destroySemaphore()
void destroySemaphore(sem_t **_sysSem ) { if (_sysSem && *_sysSem) { if (sem_destroy(*_sysSem) != 0) { perror("Semaphore Destr. failed"); } else { free(*_sysSem); *_sysSem = NULL;
}}
}
110Computer Science 213© 2006 Donald Acton
P()P()
void P(sem_t * _sysSem) { // wait, lock if (sem_wait(_sysSem) != 0) {
perror("Semaphore P() blocking");
pthread_cancel(pthread_self());
for(;;) sleep(60000);
} }
111Computer Science 213© 2006 Donald Acton
V()V()
void V(sem_t *_sysSem) { //signal, unlock
if (sem_post(_sysSem) != 0) {
perror("Sem V()blocking");
pthread_cancel(pthread_self());
for(;;) sleep(60000);
}
}
112Computer Science 213© 2006 Donald Acton
V()P()
V()
Semaphores in ActionSemaphores in Action
P()
P() V()T1
T2
T3
Time
113Computer Science 213© 2006 Donald Acton
Using P() and V() in Sort and Print ExampleUsing P() and V() in
Sort and Print Example• All threads must use the same
semaphore • Given the way we have put things
together a global variable for the semaphore will be needed
• Add code sem_t *s = createSemaphore(1);
before the definition of sortAndPrint()
114Computer Science 213© 2006 Donald Acton
Where do P() and V() go?Where do P() and V() go?
void *sortAndPrint(void *array) { int i; int *b; b = (int *) array; qsort(array, aSize, sizeof(int), cs213Compare); for (i=0; i<10; i++) { printf("%3d ", b[i]); fflush(stdout); } printf("\n"); }
115Computer Science 213© 2006 Donald Acton
Semaphores & BanksSemaphores & Banks
•Consider a banking system that has a method to transfer money from one account to another
•Uses semaphores to prevent multiple simultaneous transfers from updating the same account at once
116Computer Science 213© 2006 Donald Acton
Solution 1Solution 1
void transfer(int amt, BankA *a1, BankA *a2){
P(s);
if (valid balance) {
Withdraw(a1, amt);
Deposit(a2, amt);
}
V(s);
}
117Computer Science 213© 2006 Donald Acton
Problem with Solution 1Problem with Solution 1
• Withdraw and deposit methods could take a long time if they involve going to disk
• With a single global semaphore no other transfers can be done while waiting, even if the transfer involves completely different accounts
118Computer Science 213© 2006 Donald Acton
Solution 2Solution 2
void transfer(int amt, BankA *a1, BankA *a2){
P(a1->s); P(a2->s); if (valid balance) {
Withdraw(a1, amt);Deposit(a2, amt);
}V(a2->s); V(a1->s);
}
119Computer Science 213© 2006 Donald Acton
Does solution 2 work?Does solution 2 work?
transfer(100,a1,a2);
1. P(a1->s);
2. P(a2->s);
transfer(100,a2,a1);
1. P(a2->s);
2. P(a1->s);
At this point each thread/process is waiting for the other so no further progress, by either thread/process, can be made.
120Computer Science 213© 2006 Donald Acton
DeadlockDeadlock
Definition:A deadlock occurs when two or more processes/threads cannot make computational progress because the processes/threads, either directly or indirectly, are waiting for a resource the other process/thread holds.
121Computer Science 213© 2006 Donald Acton
Wait-for-graphWait-for-graph
– For each process draw a square– For each resource (semaphore) draw a circle– If a resource is held by a process draw an
arrow from the resource to the process – If a process is waiting for a resource draw
an arrow from the process to the resource
If a cycle exists then there is a deadlock in the system
122Computer Science 213© 2006 Donald Acton
Bank – wait-for-graphBank – wait-for-graph
123Computer Science 213© 2006 Donald Acton
Bank – wait-for-graphBank – wait-for-graph
T1 T2
a1.s
a2.s
124Computer Science 213© 2006 Donald Acton
Deadlock DetectionDeadlock Detection
• Can be done by keeping wait-for-graph
• Keeping a wait-for-graph is expensive as each time a resource is acquired, released, or waited for, the graph must be updated
• Running the cycle detection algorithm can consume many resources if it is done too frequently
125Computer Science 213© 2006 Donald Acton
So you found a deadlock, what should be done?
So you found a deadlock, what should be done?
• Something must be done otherwise the system will remain blocked
• Select one of the blocked process and return acquisition call failure
• Which process should be selected– Oldest?– One involved in the most cycles?– One involved in the least cycles?
126Computer Science 213© 2006 Donald Acton
Other StrategiesOther Strategies
• Have a timeout associated with resource acquisition– Don’t have to do deadlock detection– May timeout when there isn’t a deadlock
• Put the onus on the designer to develop deadlock free algorithms
127Computer Science 213© 2006 Donald Acton
Bank -> Deadlock FreeBank -> Deadlock Free
• All process agree to acquire resources in a specific order
128Computer Science 213© 2006 Donald Acton
LivelockLivelock
• More difficult to deal with than deadlock
• Occurs when 2 or more processes change their state in response to each other
• State change has the appearance of doing work (unlike a deadlock) but no computational progress is being made
129Computer Science 213© 2006 Donald Acton
Okay, where were we?Okay, where were we?
• Started this section out with http server
• Wanted threads to replace fork()• Can’t have an unlimited number of
threads so use a worker pool• Need semaphores to help with the
problem of sharing
130Computer Science 213© 2006 Donald Acton
HTTP Server Again!HTTP Server Again!
while (1) {accept connection
if (fork() == 0) { perform http request processing} else {
if (too many workers) { wait for worker
}}
131Computer Science 213© 2006 Donald Acton
Thread Design ModelThread Design Model
Master
threadBuffer
...
Accept
connections
Insert Request
descriptor Remove
Request
Worker
thread
Worker
thread
Client
Client
...
Service client
Service client
Pool of worker threads
Adapted from: Computer Systems: A Programmer’s Perspective
Server Machine
132Computer Science 213© 2006 Donald Acton
HTTP Server MainHTTP Server Main
main() {setup Socket to listen oninitialize semaphoresstart pool of workerswhile (1) {
accept new connectionprepare requestput request in queue
}
133Computer Science 213© 2006 Donald Acton
Worker ThreadWorker Thread
void *worker(void *data)
{
while (1) {
remove request from queue
service request
close connection
}
134Computer Science 213© 2006 Donald Acton
Queue Access RulesQueue Access Rules
Observations:– There is a single queue of requests
accessed by both the workers and main thread
– Queue has a maximum size– Main thread can only add to queue if
there is room– Worker threads can only remove
something from the queue if something is there
135Computer Science 213© 2006 Donald Acton
ProblemsProblems
• How does the main thread know if the queue is full?
• How do worker threads know if there is work to do?
136Computer Science 213© 2006 Donald Acton
Try 1: A Single SemaphoreTry 1: A Single Semaphore
• Suppose you had a single semaphore, could one determine if there was work to do?
137Computer Science 213© 2006 Donald Acton
Semaphore TricksSemaphore Tricks
• The process/thread that does a P() doesn’t have to be the one to do the V()
• Multiple V()’s can be done to increase the semaphore count – This produces a counting semaphore
and can be used when there are multiple units of a resource
138Computer Science 213© 2006 Donald Acton
Try 2 SemaphoresTry 2 Semaphores
Main ThreadP(nonempty);
Start worker(s)
while (1) {
P(empty);
add req
V(nonempty);
}
Worker Thread
while (1) {
P(nonempty);
remove req
V(empty);
}
139Computer Science 213© 2006 Donald Acton
More Workers and the Queue
More Workers and the Queue
• Works if there can be only 1 request• If we allowed N requests should we
have 1 semaphore per request/queue slot?
140Computer Science 213© 2006 Donald Acton
Try 3 SemaphoresTry 3 Semaphores1. queue – semaphore
• Used to control the shared queue access
2. nonempty – counting semaphore• Initially 0• and indicates non-empty slots
3. empty – counting semaphore• Indicates empty slots initially N• Acquired by main() for each item
added
141Computer Science 213© 2006 Donald Acton
Maintaining the QueueMaintaining the Queue
Main Threadwhile (1) {
P(empty);
P(queue);
add req
V(queue);
V(nonempty)
}
Worker Threadwhile (1){
P(nonempty);
P(queue);
remove req
V(queue);
V(empty);
}
142Computer Science 213© 2006 Donald Acton
The Missing MethodsThe Missing Methods
• Status of a thread running or dead• Setting attributes
– Permitted memory usage– Scheduling policy
• Thread specific data• Concurrency control
– Mutexes– Condition variables– Reader/writer locking
143Computer Science 213© 2006 Donald Acton
When to use fork()When to use fork()
• The task to be performed is logically separate from the “parent’s”
• Protection needed between children• e.g. command execution for a shell
– Shell doesn’t know how long command will take
– Commands are logically separate from the shell
144Computer Science 213© 2006 Donald Acton
When to use threadsWhen to use threads
• The range of actions to be performed is small
• There needs to be information sharing between the “parent” and “child” or between children