1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
[\<- Notes 02/21](02-21.md)
---
# Threading Continued
## Locking
- Sharing Variables
- Requires mutual exclusion
- Lock/unlock to avoid a race condition
- Have one lock for each independent critical region
- Bad Example (no synchronization):
```
int count = 0;
void *update(){ //returns a pointer with no given data type
int i;
for(i = 0; i < 1000; i++){
count++;
}
}
```
- Good Example (using lock):
```
int count = 0;
void *update(){ //returns a pointer with no given data type
int i;
for(i = 0; i < 1000; i++){
//lock
count++;
//unlock
}
}
```
- More real world example:
```
int balance = 100; //$100
//process 1: withdraw $20
//read balance (i.e $100)
//write new balance (i.e $80)
//process 2: withdraw $30
//read balance (i.e $80)
//write new balance (i.e $50)
```
- In the above example, you need to use lock to avoid one process reading the balance before the other process finishes writing
## pthread library
- We will use the Linux pthread library
- Main information
- `man pthread`
- There are man pages for specific functions
- Include ".h" file as shown in the man page: `#include <pthread.h>`
- Compile using `-lpthread`
- Operations:
```
#include <pthread.h>
pthread_t thread;
int pthread_create(
pthread_t *restrict thread, //thread id
const pthread_attr_t *restrict attr, //attributes
void *(*start_routine)(void *), //function
void *restrict arg); //argument
```
- More operations:
- `void pthread_exit(void *value_ptr);`
- `int pthread_join(pthread_t thread, void **value_ptr);`
- Example using pthreads
- Alternating threads
- Creates 3 threads
- Let the system execute them in a round-robin fashion
- Wait for them to finish at main
```
#include <stdio.h>
#include <pthread.h> //this is the library that allows for threading
void *loopThread(void *arg);
int main(){
int i;
pthread_t thr[3];
for(i = 0; i < 3; i++){
pthread_create(&thr[i], NULL, loopThread, (void *)i);
}
for(i = 0; i < 3; i++){
pthread_join(thr[i], NULL);
}
}
void *loopThread(void *arg){
int i, j;
int threadNo = (int)arg; //cast the void pointer
for(i = 0; i < 20; i++){
printf("Thread %d\n", threadNo);
sleep(1);
}
}
```
- Functions:
```
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
//INIT
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//LOCK
int pthread_mutex_lock(pthread_mutex_t *mutex);
//UNLOCK
int pthread_mutex_unlock(pthread_mutex_t *mutex);
```
- Example using mutex lock:
```
//Using mutex lock
//pthread_mutex_init called in main
int count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *update(){
int i;
while(i = 0; i < 1000; i++){
pthread_mutex_lock(&mutex);
count++;
pthread_mutex_unlock(&mutex);
}
}
```
- Danger!
- When one or more threads are waiting for one another and no thread can proceed
- Example:
- One thread is waiting for itself
- Two threads are waiting for each other
- Several threads are waiting for one another in a cycle
## Performance Considerations
- Thread creation is expensive
- Each thread has its own stack
- Lock contention requires skills to keep many threads as possible running
---
[-> Notes 03/04](03-04.md)
|