User Tools

Site Tools


os_cp:threads

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

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">&​amp;</​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">&​amp;</​span>​condvar<​span class="​sy0">,</​span>​ <span class="​sy0">&​amp;</​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">&​amp;</​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">&​amp;</​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">&​amp;</​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">&​amp;</​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,
os_cp/threads.1745359551.txt.gz · Last modified: 2025/04/23 00:05 by jkonczak