## Learning Objectives
* How to use threads?
* How to divide a problem into smaller subproblems?
## 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)
}
```
## What is map?
* Apply an operation to each element of a list.
### 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.
### 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);
}
```
## 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;
}
```