This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
os_cp:threads [2025/04/23 00:05] jkonczak [Critical sections, deadlocks] |
os_cp:threads [2025/04/25 13:55] (current) jkonczak [POSIX condition variables] |
||
---|---|---|---|
Line 704: | Line 704: | ||
===== Critical sections, deadlocks ===== | ===== Critical sections, deadlocks ===== | ||
- | ~~Exercise.#~~ Download and read through the {{os_cp:threads:another_bad_idea.c}} file. Which lines of code are the critical section? \\ <small>The vital parts of the file is presented below</small> | + | ~~Exercise.#~~ Download and read through the {{os_cp:threads:another_bad_idea.c}} file. Which lines of code are the critical section? \\ <small>The vital parts of the file is presented below.</small> |
~~Exercise.#~~ Spot the deadlock scenario in the code from the previous exercise. | ~~Exercise.#~~ Spot the deadlock scenario in the code from the previous exercise. | ||
Line 712: | Line 712: | ||
<html><div style="line-height:1em"></html> | <html><div style="line-height:1em"></html> | ||
<code c> | <code c> | ||
- | ⋯ | + | … |
- | 9│ #define NB_THR 5 | + | 10│ struct myIO {FILE *in; FILE *out;}; |
- | 10│ struct myIO {FILE *in; FILE *out;}; | + | 11│ void* threadFunc(void *num); |
- | 11│ void* threadFunc(void *num); | + | … |
- | ⋯ | + | 17│ struct { |
- | 17│ struct { | + | 18│ pthread_mutex_t mtx; |
- | 18│ pthread_mutex_t mtx; | + | 19│ char text[256]; |
- | 19│ char text[256]; | + | 20│ } item[5]; |
- | 20│ } item[5]; | + | 21│ |
- | 21│ | + | 22│ int main(int argc, char **argv) { |
- | 22│ int main(int argc, char **argv) { | + | … |
- | ⋯ | + | 28│ for (intptr_t i = 1; i < 5; ++i) { |
- | 28│ for (intptr_t i = 1; i < NB_THR; ++i) { | + | 29│ pthread_t tid; |
- | 29│ pthread_t tid; | + | 30│ pthread_create(&tid, NULL, threadFunc, (void *)i); |
- | 30│ pthread_create(&tid, NULL, threadFunc, (void *)i); | + | 31│ pthread_detach(tid); |
- | 31│ pthread_detach(tid); | + | 32│ } |
- | 32│ } | + | 33│ threadFunc(0); |
- | 33│ threadFunc(0); | + | 34│ } |
- | 34│ } | + | 35│ |
- | 35│ | + | 36│ void *threadFunc(void* numRaw) { |
- | 36│ void *threadFunc(void* numRaw) { | + | 37│ intptr_t num = (intptr_t) numRaw; |
- | 37│ intptr_t num = (intptr_t) numRaw; | + | 38│ struct myIO win = openWin(num); |
- | 38│ struct myIO win = openWin(num); | + | … |
- | ⋯ | + | 48│ while (1) { |
- | 49│ while (1) { | + | 49│ fprintf(win.out, "> "); |
- | 50│ char line[1024], nl; | + | 50│ |
- | 51│ fprintf(win.out, "> "); | + | 51│ char line[1024]; |
- | 53│ fscanf(win.in, "%1023[^\n]%c", line, &nl); | + | 52│ fgets(line, 1024, win.in); |
- | 54│ | + | 53│ line[strlen(line)-1] = 0; |
- | 55│ int argOne = atoi(line); | + | 54│ |
- | ⋯ | + | 55│ int argOne = atoi(line); |
- | 62│ char *argTwoTxt = strchr(line, ' '); | + | … |
- | 63│ | + | 61│ char *argTwoTxt = strchr(line, ' '); |
- | 64│ if (!argTwoTxt) { | + | 62│ |
- | 66│ pthread_mutex_lock(&item[argOne].mtx); | + | 63│ if (!argTwoTxt) { |
- | 67│ fprintf(win.out, "%d has value: %s\n", argOne, item[argOne].text); | + | 65│ pthread_mutex_lock(&item[argOne].mtx); |
- | 69│ pthread_mutex_unlock(&item[argOne].mtx); | + | 66│ fprintf(win.out, "T#%ld reads %d as: %s\n", num, argOne, item[argOne].text); |
- | 70│ continue; | + | 67│ pthread_mutex_unlock(&item[argOne].mtx); |
- | 71│ } | + | 68│ continue; |
- | 72│ | + | 69│ } |
- | 73│ argTwoTxt++; | + | 70│ |
- | 74│ char *e; | + | 71│ argTwoTxt++; |
- | 75│ int argTwo = strtol(argTwoTxt, &e, 10); | + | 72│ char *e; |
- | 76│ | + | 73│ int argTwo = strtol(argTwoTxt, &e, 10); |
- | 77│ if (!*e && argTwo < 5 && argTwo >= 0 && argOne != argTwo) { | + | 74│ |
- | 79│ pthread_mutex_lock(&item[argOne].mtx); | + | 75│ if (!*e && argTwo < 5 && argTwo >= 0 && argOne != argTwo) { |
- | 80│ pthread_mutex_lock(&item[argTwo].mtx); | + | 77│ pthread_mutex_lock(&item[argOne].mtx); |
- | 81│ fprintf(win.out, "%d gets copied to %d\n", argTwo, argOne); | + | 78│ pthread_mutex_lock(&item[argTwo].mtx); |
- | 83│ memcpy(item[argOne].text, item[argTwo].text, sizeof(item[argOne].text)); | + | 79│ fprintf(win.out, "T#%ld copies %d to %d\n", num, argTwo, argOne); |
- | 84│ pthread_mutex_unlock(&item[argTwo].mtx); | + | 80│ memcpy(item[argOne].text, item[argTwo].text, sizeof(item[argOne].text)); |
- | 85│ pthread_mutex_unlock(&item[argOne].mtx); | + | 81│ pthread_mutex_unlock(&item[argTwo].mtx); |
- | 86│ } else { | + | 82│ pthread_mutex_unlock(&item[argOne].mtx); |
- | 88│ pthread_mutex_lock(&item[argOne].mtx); | + | 83│ } else { |
- | 89│ fprintf(win.out, "%d is set to: %s\n", argOne, argTwoTxt); | + | 85│ pthread_mutex_lock(&item[argOne].mtx); |
- | 91│ memset(item[argOne].text, 0, sizeof(item[argOne].text)); | + | 86│ fprintf(win.out, "T#%ld assigns to %d the value: %s\n", num, argOne, argTwoTxt); |
- | 92│ strncpy(item[argOne].text, argTwoTxt, sizeof(item[argOne].text) - 1); | + | 87│ memset(item[argOne].text, 0, sizeof(item[argOne].text)); |
- | 93│ pthread_mutex_unlock(&item[argOne].mtx); | + | 88│ strncpy(item[argOne].text, argTwoTxt, sizeof(item[argOne].text) - 1); |
- | 94│ } | + | 89│ pthread_mutex_unlock(&item[argOne].mtx); |
- | 95│ } | + | 90│ } |
- | 96│ } | + | 91│ } |
- | ⋯ | + | 92│ } |
+ | … | ||
</code> | </code> | ||
<html></div></html> | <html></div></html> | ||
Line 876: | Line 877: | ||
When one thread needs to execute some logic once a specific condition is fulfilled, | When one thread needs to execute some logic once a specific condition is fulfilled, | ||
it should: | it should: | ||
+ | <html><div style="margin-top:-1.2em"></div></html> | ||
+ | <WRAP group> | ||
+ | <WRAP half column> | ||
- lock a mutex, | - lock a mutex, | ||
- check the condition, | - check the condition, | ||
- | - if the condition is false: | + | - while the condition is false: |
- wait on a condition variable, | - wait on a condition variable, | ||
- go back to step 2, | - go back to step 2, | ||
- do the logic, | - do the logic, | ||
- unlock the mutex. | - unlock the mutex. | ||
+ | </WRAP> | ||
+ | <WRAP half column> | ||
+ | <html> | ||
+ | <pre class="code c" style="margin-top:-1.4em;margin-bottom:-1.4em;"> | ||
+ | <span style="opacity:0.66">pthread_mutex_</span>lock<span class="br0">(</span><span class="sy0">&</span>mutex<span class="br0">)</span><span class="sy0">;</span> | ||
+ | <span class="kw1">while</span><span class="br0">(</span><span class="sy0">!</span><i>condition</i><span class="br0">)</span> | ||
+ | <span style="opacity:0.66">pthread_cond_</span>wait<span class="br0">(</span><span class="sy0">&</span>condvar<span class="sy0">,</span> <span class="sy0">&</span>mutex<span class="br0">)</span><span class="sy0">;</span> | ||
+ | <i>logic<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></i> | ||
+ | <span style="opacity:0.66">pthread_mutex_</span>unlock<span class="br0">(</span><span class="sy0">&</span>mutex<span class="br0">)</span><span class="sy0">;</span> | ||
+ | </pre> | ||
+ | </html> | ||
+ | </WRAP> | ||
+ | </WRAP> | ||
A thread that may change the state and thus affect the condition should: | A thread that may change the state and thus affect the condition should: | ||
+ | <html><div style="margin-top:-1.2em"></div></html> | ||
+ | <WRAP group> | ||
+ | <WRAP half column> | ||
- lock the mutex, | - lock the mutex, | ||
- do its logic, | - do its logic, | ||
- signal the condition variable, | - signal the condition variable, | ||
- unlock the mutex((One can also signal the condition variable after unlocking the mutex.)). | - unlock the mutex((One can also signal the condition variable after unlocking the mutex.)). | ||
+ | </WRAP> | ||
+ | <WRAP half column> | ||
+ | <html> | ||
+ | <pre class="code c" style="padding-top:0; padding-bottom:0; margin-top:-1.4em;margin-bottom:-1.4em;"> | ||
+ | <span style="opacity:0.66">pthread_mutex_</span>lock<span class="br0">(</span><span class="sy0">&</span>mutex<span class="br0">)</span><span class="sy0">;</span> | ||
+ | <i>logic_that_changes_condition<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></i> | ||
+ | <span style="opacity:0.66">pthread_cond_</span>signal<span class="br0">(</span><span class="sy0">&</span>condvar<span class="br0">)</span><span class="sy0">;</span> | ||
+ | <span style="opacity:0.66">pthread_mutex_</span>unlock<span class="br0">(</span><span class="sy0">&</span>mutex<span class="br0">)</span><span class="sy0">;</span> | ||
+ | </pre> | ||
+ | </html> | ||
+ | </WRAP> | ||
+ | </WRAP> | ||
<small> | <small> | ||
The example conditions include: | The example conditions include: | ||
+ | <html><div style="margin-top:-1.2em"></div></html> | ||
* a boolean flag is set; the flag indicates that another thread finished a part of the computation and the results can used, | * a boolean flag is set; the flag indicates that another thread finished a part of the computation and the results can used, | ||
* a list of items is not empty; the list contains tasks to be done by this thread, | * a list of items is not empty; the list contains tasks to be done by this thread, |