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)

 

EXAMPLES:

 

âthrd-posix.c:

 

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

 

â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  10

 

Java Threads

ü Java threads are managed by the JVM

ü Typically implemented using the threads model provided by underlying OS

 

EXAMPLES:

 

â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

 

 

 


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:

â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;


    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.

 

â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(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.