## Learning Objectives * How to use threads? * How to divide a problem into smaller subproblems?
# Threads
## Pthread Review * Create pthread ```c++ int pthread_create(pthread_t* thread, const pthread_attr_t *attr, void *(start_routine)(void*), void *arg) ``` * __thread__ : thread id, returned by pthread_create * __attr__: some attributes of the thread. * __start_routine__: function invoked by the thread. * __arg__: arguments you want to send to your start_routine
## Pthread Review * Using pthreads ```c++ void* map(void* args); int main() { size_t num_threads = 5; pthraed_attr_t attr; int s = pthread_attr_init(&attr); pthread_t* pids = (pthread_t*) malloc(sizeof(pthread_t)*num_threads); int arr[5] = {1,2,3,4,5}; for(size_t i = 0 ; i < num_threads; ++i) { pthread_create(pids+i, attr, map, (void*) arr); } for(size_t i = 0; i < num_threads; ++i) { pthread_join(pids[i], NULL); } return 0; } ```
## Pthread Review * Join pthreads and clean up resources ```c++ int pthread_join(pthread_t thread, void ** valueptr); int main() { // Some setup... pthread_create(&pid, attr, foo, args); // ... // The main thread will stuck here until // the thread finish it's job. // Use NULL if you don't need the return value. pthread_join(&pid, NULL); } ```
## Pthread Review * What if I want to pass multiple parameters? ```c++ typedef struct { int a; char *b; } MyArgs; void* foo (void* args) { MyArgs* ptr = (MyArgs*) args; // do something } int main(){ // some setting .. MyArgs arg; arg.a = 1; arg.b = NULL; pthread_create(pid, attr, foo, (void*)&arg) } ```
# Map
## What is map? * Apply an operation to each element of a list.

Map

### Example ```c++ void doubleMapper(int* arr, size_t arr_size) { size_t i = 0; for(; i< arr_size; ++i){ arr[i] = arr[i]*2; } return arr[i]; } int main() { int arr[5] ={1,2,3,4,5}; doubleMapper(arr, 5); printArr(arr, 5); } ``` Result ``` wlee114@fa16-cs241-xxx:~/Tests$ ./a.out 2 4 6 8 10 ```
## Pararrel Mapping * Let each thread work on an item.

Map

### Example ```c++ void parMapper(int* arr, size_t arr_size) { // Create thread pthread_create(...) // thread 1 double arr[0] // thread 2 double arr[1] // ... // Join the thread pthread_join(...) } int main() { int arr[5] ={1,2,3,4,5}; parMapper(arr, 5); printArr(arr, 5); } ```
# Par Map
## Design * What if I want to triple each element? * What if I want to square each element? * What if I want to 'do some job' on each element?
## Design * I don't want to implement the paralle part every time. * I just want to change my operation.
### Example ```c++ // My operation double triple(double elem); double negate(double elem); // Parallel function double* par_map(double* list, size_t len, mapper foo, size_t num_threads){ // generate threads // thread[0] apply foo on list[0]-list[10] // thread[1] apply foo on list[11]-list[20] // ... } int main() { double arr[3] = {1.,2.,3.}; // triple my elements double *rev = par_map(arr, 3, triple, 2); return 0; } ```