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)
EXAMPLES:
int sum; /* this data is shared by the
thread(s) */
void *runner(void *param); /* the thread */
int main(int argc, char *argv[])
{
pthread_t tid; /*
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]);
/* now wait for the thread to exit */
pthread_join(tid, NULL);
printf("sum = %d\n", sum);
}
void *runner(void *param)
{
int
i, upper = atoi(param);
sum = 0;
if (upper > 0) {
for (i = 1; i <= upper; i++)
sum += i;
}
pthread_exit(0);
}
To execute:
% thrd-posix 10
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 10
Java Threads
ü
Java threads are
managed by the JVM
ü
Typically
implemented using the threads model provided by underlying OS
EXAMPLES:
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
![]()
Threading Issues
·
Semantics
of fork() and exec()
Does fork()
duplicate only the calling thread or all threads?
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
Signals are
used in UNIX systems to notify a process that a particular event has occurred
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 1: thread-fork.c
int main(int argc, char *argv[])
{
signal(SIGINT, SIG_IGN);
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;
signal(SIGINT, SIGhandler1);
for(i=0;i<=7;i++) {
printf("HI
%d\n", i);
sleep(i);
}
}
void *runner2()
{
int i;
signal(SIGINT, SIGhandler2);
for(i=0;i<=7;i++) {
printf("HI
%c\n", i+'a');
sleep(i);
}
}
void SIGhandler1(int
sig)
{
signal(sig,
SIGhandler1);
psignal(sig,
"Received SIGhandler1
signal");
printf("thread
PID: %d\n", getpid());
}
void SIGhandler2(int
sig)
{
signal(sig,
SIGhandler2);
psignal(sig,
"Received SIGhandler2
signal");
printf("child
process PID: %d\n", getpid());
}
To execute:
%
thread-fork
Type: CTRL-C
Received SIGhandler1 signal: Interrupt
thread PID: 20068
Received SIGhandler2 signal: Interrupt
child process PID: 20073
To exit type: CTRL-\
âExample 2: thread-signal.c
int main(int argc, char *argv[])
{
signal(SIGINT, SIG_IGN);
pthread_create(&tid1, &attr, runner1, 0);
pthread_create(&tid2, &attr, runner2, 0);
runner0();
pthread_join(tid1,
NULL);
printf("thread1
done\n");
pthread_join(tid2,
NULL);
printf("thread2
done\n");
}
void *runner0()
{
int i;
printf("\nParent
Process, PID: %d\n", getpid());
for(i=0;i<=7;i++) {
printf("HI %c\n", i+'A');
sleep(i);
}
}
void *runner1()
{
int i;
signal(SIGINT, SIGhandler1);
printf("\nThread1,
PID: %d\n", getpid());
for(i=0;i<=7;i++) {
printf("HI
%d\n", i);
sleep(i);
}
}
void *runner2()
{
int i;
signal(SIGINT, SIGhandler2);
printf("\nThread2,
PID: %d\n", getpid());
for(i=0;i<=7;i++) {
printf("HI
%c\n", i+'a');
sleep(i);
}
}
void SIGhandler1(int sig)
{
signal(sig,
SIGhandler1);
printf("\nPID:
%d", getpid());
psignal(sig,
"\nReceived SIGhandler1 signal");
printf("pauseing...\n\n");
pause();
}
void SIGhandler2(int sig)
{
signal(sig,
SIGhandler2);
printf("\nPID:
%d", getpid());
psignal(sig,
"\nReceived SIGhandler2 signal");
printf("pauseing...\n\n");
pause();
}
To execute:
%
thread-signal
Type: CTRL-C
PID: 18672
Received
SIGhandler2 signal: Interrupt
pauseing...
To exit type: CTRL-\
·
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
·
Thread
Specific Data
Allows each
thread to have its own copy of data
Useful when
you do not have control over the thread creation process (i.e., when using a
thread pool)
![]()
EXAMPLES
of Threaded Servers:
int
main(void)
{
int len, listenfd, connfd;
struct sockaddr_in servaddr, cliaddr;
char buff[512];
int nread;
pthread_t tid;
pthread_attr_t attr;
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);
pthread_attr_init(&attr);
for (;;) {
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA *)
& cliaddr, &len);
printf("connetion 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 10123
ü In another window for
the same host:
% EchoClientFork localhost 10123
ü 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(10123);
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 10123
ü In another window
for the same host:
% EchoClientFork localhost 10123
ü Repeat for any number of other
windows.