Single and Multithreaded Processes
Benefits: Responsiveness & Resource Sharing
Multithreaded
Server Architecture
Pthreads
ü
A
POSIX standard API for thread creation and synchronization
ü
Common
in UNIX operating systems (Solaris, Linux, Mac OS X
Thread Functions:
pthread_create (ThreadID, Priority,
Starting Function, Function Args)
pthread_join
// similar to waitpid
pthread_self
// similar to getpid
pthread_detach // not joinable
pthread_exit // terminate
a thread;
// calling exit() kills ALL threads.
pthread_cancel (ThreadID) //cancel a thread
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
EXAMPLE:
int sum; /* this data is shared by the thread(s) */
int
sum2; /* this data is shared by
the thread(s) */
void *runner(void *param); /* the
thread */
void *runner2(void *param); /* the thread
*/
int main(int argc, char *argv[])
{
pthread_t tid; /* the thread identifier */
pthread_t tid2; /*
the thread identifier */
pthread_attr_t attr; /* set of attributes for the thread */
/* get the default attributes */
pthread_attr_init(&attr);
/* create the thread */
pthread_create(&tid, &attr, runner, argv[1]);
/* create the 2nd thread */
pthread_create(&tid2,
&attr, runner2, argv[1]);
/* now wait for the thread to exit */
pthread_join(tid, NULL);
pthread_join(tid2,
NULL);
printf("sum
= %d\n", sum);
printf("sum2
= %d\n", sum2);
}
void *runner(void *param)
{
int i, upper
= atoi(param);
sum = 0;
if (upper >= 0) {
for (i
= 0; i <= upper; i++) {
sum += i;
}
}
pthread_exit(0);
}
void *runner2(void *param)
{
int i, upper
= atoi(param);
sum2 = 0;
if (upper >= 0) {
for (i
= 0; i <= upper; i++) {
sum2 += pow(2, i);
}
}
pthread_exit(0);
}
To execute:
%
thrd2-posix 1
sum = 1
sum2 = 3
%
thrd2-posix 20
sum = 210
sum2 =
2097151
EXAMPLE:
static void *thread_func(void
*ignored_argument)
{
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
sleep(5);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
sleep(1000);
printf("thread_func(): not
canceled!\n");
}
main(void)
{
pthread_t
thr;
void
*res;
pthread_create(&thr, NULL, &thread_func,
NULL);
sleep(2);
pthread_cancel(thr);
pthread_join(thr,
&res);
if (res ==
PTHREAD_CANCELED)
printf("thread
canceled\n");
}
To execute:
% thread-cancel
Java
Threads
ü
Java threads are
managed by the JVM
ü
Typically
implemented using the threads model provided by underlying OS
EXAMPLE:
public class SimpleThread extends Thread {
private int countDown = 50;
private static int
threadCount = 0;
private int
threadNumber = ++threadCount;
public SimpleThread() {
System.out.println("Making " + threadNumber);
}
public void run()
{
while(true) {
System.out.println("Thread " +
threadNumber + "("
+ countDown + ")");
if(--countDown == 0) return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new
SimpleThread().start();
System.out.println("All Threads Started");
}
}
To execute:
% java
SimpleThread
Python
Threads
EXAMPLE:
#! /usr/bin/python
import threading
import datetime
class ThreadClass(threading.Thread):
def run(self):
now = datetime.datetime.now()
print ("%s says Hello World
at time: %s\n" %
(self.getName(),
now))
for i in range(2):
t = ThreadClass()
t.start()
To execute:
%
SimpleThread.py
Threading Issues
·
Semantics of fork() and exec()
Does fork() duplicate only the calling thread or
all threads?
Answer:
No, it does not duplicate any of the threads.
Example: thread-fork.c
main(int argc,
char *argv[])
{
pthread_create(&tid, &attr, runner1,
0);
if
( fork() == 0){
runner2();
exit(0);
}
else
{
pthread_join(tid, NULL);
printf("thread
done\n");
wait(NULL);
printf("child process done\n");
}
}
void *runner1()
{
int i;
for(i=0;i<=7;i++) {
printf("HI %d\n", i);
sleep(i);
}
}
void *runner2()
{
int i;
for(i=0;i<=7;i++) {
printf("HI %c\n", i+'a');
sleep(i);
}
}
To execute:
%
thread-fork
HI 0
HI 1
HI a
HI b
HI 2
HI c
HI d
HI 3
HI e
HI 4
HI f
HI 5
Etc...
Signal
Handling
A signal
handler is used to process signals
Signal is
generated by particular event
Signal is
delivered to a process
Options:
Deliver the
signal to the thread to which the signal applies
Deliver the
signal to every thread in the process
Deliver the
signal to certain threads in the process
Assign a
specific thread to receive all signals for the process
In UNIX:
·
The
signal is delivered to EVERY process in the program
· The parent process of all threads gets
the signal and NONE of the
threads gets it.
Example : thread-signal.c
int
main(int argc, char *argv[])
{
pthread_t tid1;
pthread_t tid2;
pthread_attr_t attr;
int i;
signal(SIGINT, SIGhandler0);
pthread_attr_init(&attr);
pthread_create(&tid1,
&attr, runner1, 0);
pthread_create(&tid2,
&attr, runner2, 0);
for(;;){
printf("Main
Thread %c%c\n", (i++)%26
+'a', (i)%26 +'A');
sleep(1);
}
}
void *runner1()
{
int i=0;
signal(SIGINT, SIGhandler1);
for(;;){
printf("thread
1 %c\n", (i++)%26 +'a');
sleep(1);
}
}
void *runner2()
{
int i=0;
signal(SIGINT, SIGhandler2);
for(;;){
printf("THREAD2 %c\n", (i++)%26
+'A');
sleep(1);
}
}
void SIGhandler0(int sig)
{
signal(sig, SIGhandler0);
psignal(sig,
"\nReceived SIGhandler0 signal");
}
void SIGhandler1(int sig)
{
signal(sig, SIGhandler1);
psignal(sig,
"\nReceived SIGhandler1 signal");
}
void SIGhandler2(int sig)
{
signal(sig, SIGhandler2);
psignal(sig,
"\nReceived SIGhandler2 signal");
}
To execute:
% thread-signal
Type: CTRL-C
OR
Type: CTRL-\ to exit
Example : fork-thread-signal.c
int main(int
argc, char *argv[])
{
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
signal(SIGINT, SIG_IGN);
if ( fork() == 0){
childrunner();
exit(0);
}
else {
pthread_create(&tid, &attr, threadrunner,
0);
pthread_join(tid, NULL);
printf("thread
done\n");
wait(NULL);
printf("child process done\n");
}
}
void childrunner()
{
int i=0;
signal(SIGINT, SIGhandlerChild);
for(;;){
printf("CHILD
%c\n", (i++)%26 + 'A');
sleep(i);
}
}
void *threadrunner()
{
int i=0;
signal(SIGINT, SIGhandlerThread);
for(;;){
printf("thread
%c\n", (i++)%26 +'a');
sleep(i);
}
}
void SIGhandlerChild(int sig)
{
signal(sig, SIGhandlerChild);
psignal(sig,
"Received SIGhandlerChild
signal");
printf("Child
PID: %d\n", getpid());
}
void SIGhandlerThread(int
sig)
{
signal(sig, SIGhandlerThread);
psignal(sig,
"Received SIGhandlerThread
signal");
printf("Thread
PID: %d\n", getpid());
}
To execute:
% fork-thread-signal
Type: CTRL-C
OR
Type: CTRL-\ to exit
Thread
Pools
Create a
number of threads in a pool where they await work
Advantages:
Usually
slightly faster to service a request
with an existing thread than create a new thread
Allows the
number of threads in the application(s) to be bound to the size of the pool
EXAMPLES of Threaded Servers:
NOTE:
If the default port 10117 is used, use any other port as an
argument to the server,
For example:
%
EchoServerThread 10321
Int main(void)
{
int len, listenfd, connfd;
struct sockaddr_in servaddr, cliaddr;
char buff[512];
int nread;
pthread_t tid;
pthread_attr_t attr;
if ( (listenfd
= socket(AF_INET,
SOCK_STREAM, 0)) == -1 ) {
printf ("error\n");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family
= AF_INET;
servaddr.sin_addr.s_addr
= htonl(INADDR_ANY);
servaddr.sin_port
= htons(10117);
if ( bind(listenfd, (SA *)
& servaddr, sizeof(servaddr)) < 0) {
printf("can not bind\n");
exit(-1);
}
listen(listenfd, 0);
pthread_attr_init(&attr);
for (;;) {
len = sizeof(cliaddr);
connfd
= accept(listenfd, (SA *) & cliaddr,
&len);
printf("connection
from: %s:%d\n", inet_ntoa(cliaddr.sin_addr),
ntohs(cliaddr.sin_port));
pthread_create(&tid, &attr, &EchoToClient, (void *) connfd);
}
}
void *EchoToClient(void
*sockfd)
{
int nread;
char buffer[512];
for (;;) {
nread
= read((int) sockfd, buffer, 512);
if (nread == 0)
pthread_exit(0);
// exit(0);
write((int) sockfd, buffer, nread);
}
}
To execute:
%
EchoServerThread
ü In another window for the same host:
%
EchoClientFork localhost 10117
ü In another window for the same host:
%
EchoClientFork localhost 10117
ü Repeat for
any number of other windows.
class EchoToClient extends
Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public EchoToClient(Socket s) throws IOException {
socket = s;
in = new BufferedReader( new
InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(
new BufferedWriter(
new
OutputStreamWriter(socket.getOutputStream())),
true);
start();
}
public void run() {
try {
while (true) {
String
str = in.readLine();
if
(str.length() == 0 )
System.exit(0);
else
out.println(str);
}
} catch(IOException e) {
}
}
}
public class
EchoServerThreadJava {
public static void main(String[] args)
throws IOException {
ServerSocket
s = new ServerSocket(10117);
try {
while(true) {
Socket
socket = s.accept();
try {
new EchoToClient (socket);
} catch(IOException e) {
}
}
} catch(IOException e) {
}
}
}
To execute:
% java EchoServerThreadJava
ü In another window for the same host:
%
EchoClientFork localhost 10117
ü In another window for the same host:
%
EchoClientFork localhost 10117
ü Repeat for
any number of other windows.
#! /usr/bin/env python
import socket
import sys
import os
import threading
def EchoThread(conn,addr):
while (1):
data = conn.recv(1000000)
if not data:
break
print 'received', len(data), 'bytes: ', data
conn.send(data)
conn.close()
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
threading.Thread(target=EchoThread,args=(conn,addr)).start()
To execute:
%
EchoServerThread.py
ü In another window for the same host:
%
EchoClientFork localhost 10117
ü In another window for the same host:
% EchoClientFork localhost 10117
ü Repeat for
any number of other windows.