32
1 Unix Threads & Concurrency Erick Fredj Computer Science The Jerusalem College of Technology

Unix Threads & Concurrency - BIUu.cs.biu.ac.il/~myghaz/Sadna/U09_lecture08.pdf · 29 Mutex Variable in Threads Program /* The main program creates threads which do all the work and

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

1

Unix

Threads & Concurrency

Erick Fredj

Computer Science

The Jerusalem College of Technology

2

Threads

Processes have the following components:

an address space

a collection of operating system state

a CPU context … or thread of control

On multiprocessor systems, with several CPUs, it would make sense for a process to have several CPU contexts (threads of control)

Multiple threads of control could run in the same address space on a single CPU system too!

“thread of control” and “address space” are orthogonal concepts

3

Threads

Threads share a process address space with zero or more other threads

Threads have their own PC, SP, register state etc stack

A traditional process can be viewed as an address space with a single thread

4

Single thread state within a process

5

Multiple threads in an address space

6

What is a thread?

A thread executes a stream of instructions an abstraction for control-flow

Practically, it is a processor context and stack Allocated a CPU by a scheduler

Executes in the context of a memory address space

7

Summary of private per-thread state

Stack (local variables)

Stack pointer

Registers

Scheduling properties (i.e., priority)

Set of pending and blocked signals

Other thread specific data

8

Shared state among threads

Open files, sockets, locks

User ID, group ID, process/task ID

Address space Text

Data (off-stack global variables)

Heap (dynamic data)

Changes made to shared state by one thread will be visible to the others Reading and writing memory locations requires

synchronization! … a major topic for later …

9

How do you program using threads?

Split program into routines to execute in parallel

True or pseudo (interleaved) parallelism

10

Why program using threads?

Utilize multiple CPU’s concurrently

Low cost communication via shared memory

Overlap computation and blocking on a single CPU Blocking due to I/O

Computation and communication

Handle asynchronous events

11

Thread usage

A word processor with three threads

12

Common thread programming models

Manager/worker

Manager thread handles I/O and assigns work to worker threads

Worker threads may be created dynamically, or allocated from a thread-pool

Peer

Like manager worker, but manager participates in the work

Pipeline

Each thread handles a different stage of an assembly line

Threads hand work off to each other in a producer-consumer relationship

13

What does a typical thread API look like?

POSIX standard threads (Pthreads)

First thread exists in main(), typically creates the others

pthread_create (thread,attr,start_routine,arg) Returns new thread ID in “thread”

Executes routine specified by “start_routine” with argument specified by “arg”

Exits on return from routine or when told explicitly

14

Thread API (continued)

pthread_exit (status)

Terminates the thread and returns “status” to any joining thread

pthread_join (threadid,status)

Blocks the calling thread until thread specified by “threadid” terminates

Return status from pthread_exit is passed in “status”

One way of synchronizing between threads

pthread_yield ()

Thread gives up the CPU and enters the run queue

15

Using create, join and exit primitives

16

An example Pthreads program

#include <pthread.h>#include <stdio.h>#define NUM_THREADS 5

void *PrintHello(void *threadid){printf("\n%d: Hello World!\n", threadid);pthread_exit(NULL);

}

int main (int argc, char *argv[]){pthread_t threads[NUM_THREADS];int rc, t;for(i=0; i<NUM_THREADS; i++){

printf("Creating thread %d\n", t);rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);if (rc){

printf("ERROR; return code from pthread_create() is %d\n", rc);exit(-1);

}}pthread_exit(NULL);

}

Program Output

Creating thread 0Creating thread 10: Hello World!1: Hello World!Creating thread 2Creating thread 32: Hello World!3: Hello World!Creating thread 44: Hello World!

For more examples see: http://www.llnl.gov/computing/tutorials/pthreads

17

Thread Argument Passing

#include <pthread.h>#include <stdio.h>#include <stdlib.h>#define NUM_THREADS 3

char *messages[NUM_THREADS];struct thread_data{ int thread_id; int sum; char *message;};

struct thread_data thread_data_array[NUM_THREADS];

18

Thread Argument Passing

void *PrintHello(void *threadarg){

int taskid, sum;char *hello_msg;struct thread_data *my_data; sleep(1);my_data = (struct thread_data *) threadarg;taskid = my_data->thread_id;sum = my_data->sum; hello_msg = my_data->message;printf("Thread %d: %s Sum=%d\n", taskid, hello_msg, sum);pthread_exit(NULL);

}

19

Thread Argument Passing

int main(int argc, char *argv[])

{

pthread_t threads[NUM_THREADS];

int *taskids[NUM_THREADS];

int rc, t, sum;

sum=0;

messages[0] = "English: Hello World!";

messages[1] = "French: Bonjour, le monde!";

messages[2] = "Spanish: Hola al mundo";

for(t=0;t<NUM_THREADS;t++) {

sum = sum + t;

thread_data_array[t].thread_id = t;

thread_data_array[t].sum = sum;

thread_data_array[t].message = messages[t];

printf("Creating thread %d\n", t);

rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&thread_data_array[t]);

if (rc) {

printf("ERROR; return code from pthread_create() is %d\n", rc);

exit(-1);

}

}

pthread_exit(NULL);

}

20

Pthread Joining

#include <pthread.h>#include <stdio.h>#include <stdlib.h>#define NUM_THREADS 3

void *BusyWork(void *null){

int i;

double result=0.0;

for (i=0; i<1000000; i++){

result = result + (double)random();}printf("Thread result = %e\n",result);pthread_exit((void *) 0);

}

21

Pthread Joining

int main(int argc, char *argv[]){

pthread_t thread[NUM_THREADS];pthread_attr_t attr;int rc, t, status;

/* Initialize and set thread detached attribute */pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

for(t=0;t<NUM_THREADS;t++){

printf("Creating thread %d\n", t);rc = pthread_create(&thread[t], &attr, BusyWork, NULL); if (rc){

printf("ERROR; return code from pthread_create() is %d\n", rc);exit(-1);

}}

22

Pthread Joining

/* Free attribute and wait for the other threads */pthread_attr_destroy(&attr);for(t=0;t<NUM_THREADS;t++){

rc = pthread_join(thread[t], (void **)&status);if (rc){

printf("ERROR return code from pthread_join() is %d\n", rc);exit(-1);

}printf("Completed join with thread %d status= %d\n",t, status);

}

pthread_exit(NULL);}

23

Stack Management

#include <pthread.h>#include <stdio.h>#define NTHREADS 4#define N 1000#define MEGEXTRA 1000000 pthread_attr_t attr;void *dowork(void *threadid){

double A[N][N];int i,j; size_t mystacksize;pthread_attr_getstacksize (&attr, &mystacksize);

printf("Thread %d: stack size = %d bytes \n", threadid, mystacksize);for (i=0; i<N; i++)

for (j=0; j<N; j++)A[i][j] = ((i*j)/3.452) + (N-i);

pthread_exit(NULL);}

24

Stack Management

int main(int argc, char *argv[]){pthread_t threads[NTHREADS];size_t stacksize;int rc, t;pthread_attr_init(&attr);

pthread_attr_getstacksize (&attr, &stacksize);printf("Default stack size = %d\n", stacksize);stacksize = sizeof(double)*N*N+MEGEXTRA;printf("Amount of stack needed per thread = %d\n",stacksize);pthread_attr_setstacksize (&attr, stacksize);printf("Creating threads with stack size = %d bytes\n",stacksize);for(t=0; t<NTHREADS; t++){

rc = pthread_create(&threads[t], &attr, dowork, (void *)t);if (rc){

printf("ERROR; return code from pthread_create() is %d\n", rc);exit(-1);

}}printf("Created %d threads.\n", t);pthread_exit(NULL);

}

25

Mutex Variable in Threads Program

#include <pthread.h>#include <stdio.h>#include <stdlib.h>

/* The following structure contains the necessary information to allow the function "dotprod" to access its input data and place its output into the structure. This structure is unchanged from the sequential version.*/

typedef struct {

double *a;double *b;double sum; int veclen;

} DOTDATA;

26

Mutex Variable in Threads Program

/* Define globally accessible variables and a mutex */

#define NUMTHRDS 4#define VECLEN 100

DOTDATA dotstr; pthread_t callThd[NUMTHRDS];pthread_mutex_t mutexsum;

27

Mutex Variable in Threads Program

/*The function dotprod is activated when the thread is created. As before, all input to this routine is obtained from a structure of type DOTDATA and all output from this function is written intothis structure. The benefit of this approach is apparent for the multi-threaded program: when a thread is created we pass a single argument to the activated function -typically this argumentis a thread number. All the other information required by the function is accessed from the globally accessible structure. */

void *dotprod(void *arg){

/* Define and use local variables for convenience */

int i, start, end, offset, len ;double mysum, *x, *y;offset = (int)arg;

len = dotstr.veclen;start = offset*len;end = start + len;x = dotstr.a;y = dotstr.b;

28

Mutex Variable in Threads Program

/*Perform the dot product and assign resultto the appropriate variable in the structure. */

mysum = 0;for (i=start; i<end ; i++) {

mysum += (x[i] * y[i]);}

/*Lock a mutex prior to updating the value in the sharedstructure, and unlock it upon updating.*/

pthread_mutex_lock (&mutexsum);dotstr.sum += mysum;pthread_mutex_unlock (&mutexsum);

pthread_exit((void*) 0);}

29

Mutex Variable in Threads Program

/* The main program creates threads which do all the work and then print out result upon completion. Before creating the threads, The input data is created. Since all threads update a shared structure, weneed a mutex for mutual exclusion. The main thread needs to wait for all threads to complete, it waits for each one of the threads. We specify a thread attribute value that allow the main thread to join with thethreads it creates. Note also that we free up handles when they are no longer needed.*/

int main (int argc, char *argv[]){int i;double *a, *b;int status;pthread_attr_t attr;

/* Assign storage and initialize values */

a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));

for (i=0; i<VECLEN*NUMTHRDS; i++) {a[i]=1;b[i]=a[i];}

30

Mutex Variable in Threads Program

dotstr.veclen = VECLEN; dotstr.a = a; dotstr.b = b; dotstr.sum=0;pthread_mutex_init(&mutexsum, NULL);/* Create threads to perform the dotproduct */pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);for(i=0;i<NUMTHRDS;i++)

{/* Each thread works on a different set of data.* The offset is specified by 'i'. The size of* the data for each thread is indicated by VECLEN.*/pthread_create( &callThd[i], &attr, dotprod, (void *)i); }

pthread_attr_destroy(&attr);

31

Mutex Variable in Threads Program

/* Wait on the other threads */for(i=0;i<NUMTHRDS;i++) {

pthread_join( callThd[i], (void **)&status);}

/* After joining, print out the results and cleanup */printf ("Sum = %f \n", dotstr.sum);free (a);free (b);pthread_mutex_destroy(&mutexsum);pthread_exit(NULL);}

32

Pros & cons of threads

Pros Overlap I/O with computation!

Cheaper context switches

Better mapping to shared memory multiprocessors

Cons Potential thread interactions

Complexity of debugging

Complexity of multi-threaded programming

Backwards compatibility with existing code