Threads

 

Single and Multithreaded Processes

 

 

 

Benefits: Responsiveness & Resource Sharing

 

 

Multithreaded Server Architecture

 

 

 

 

Description: 4

 

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:

thrd2-posix.c:

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:

thread-cancel.c:



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:

 

SimpleThread.java:

 

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:

 

SimpleThread.py:

 

#! /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

EchoServerThread.c:

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.

 

EchoServerThreadJava:

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.

 

EchoServerThread.py:

#! /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.