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)
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
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
![]()
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-signal.c
int
main(int argc, char *argv[])
{
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
signal(SIGINT, SIG_IGN);
pthread_create(&tid, &attr, ThreadRunner,
0);
if (fork() == 0) {
ChildRunner();
exit(0);
}
ParentRunner();
wait(NULL);
printf("child process done\n");
pthread_join(tid, NULL);
printf("thread
done\n");
}
void *ParentRunner()
{
int i;
printf("\nParentRunner started, PID: %d\n", getpid());
for(i=0;i<=7;i++)
{
printf("Parent:
%c\n", i+'A');
sleep(i);
}
}
void *ThreadRunner()
{
int i;
signal(SIGINT, ThreadSIGhandler);
printf("\nThreadRunner started, PID: %d\n", getpid());
for(i=0;i<=7;i++)
{
printf("Thread:
%d\n", i);
sleep(i);
}
}
void *ChildRunner()
{
int i;
signal(SIGINT, ChildSIGhandler);
printf("\nChildRunner started, PID: %d\n", getpid());
for(i=0;i<=7;i++)
{
printf("Child:
%c\n", i+'a');
sleep(i);
}
}
void ThreadSIGhandler(int sig)
{
signal(sig, ThreadSIGhandler);
printf("\nPID: %d", getpid());
psignal(sig,
"\nReceived ThreadSIGhandler
signal");
printf("pauseing...\n\n");
pause();
}
void ChildSIGhandler(int sig)
{
signal(sig, ChildSIGhandler);
printf("\nPID: %d", getpid());
psignal(sig,
"\nReceived ChildSIGhandler
signal");
printf("pauseing...\n\n");
pause();
}
To execute:
%
thread-fork-signal
Type: CTRL-C
·
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;
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(10123);
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 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.