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 revisionPrevious revision
Next revision
Previous revision
os_cp:threads [2025/04/16 19:57] – jkonczakos_cp:threads [2025/04/25 11:55] (current) – [POSIX condition variables] jkonczak
Line 704: Line 704:
 ===== Critical sections, deadlocks ===== ===== Critical sections, deadlocks =====
  
-~~Exercise.#~~ Which lines of code are the critical section in the code below?+~~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 below.+~~Exercise.#~~ Spot the deadlock scenario in the code from the previous exercise.
  
 ~~Exercise.#~~ Fix the code so that it no longer is able to deadlock. ~~Exercise.#~~ Fix the code so that it no longer is able to deadlock.
  
-<html><div style="line-height:1.2em"></html> +<html><div style="line-height:1em"></html> 
-<small> +<code c> 
-<code c another_bad_idea.c> +  … 
-#include <pthread.h> +10│ struct myIO {FILE *in; FILE *out;}; 
-#include <stdint.h> +11│ void* threadFunc(void *num); 
-#include <stdio.h> +  … 
-#include <stdlib.h> +17│ struct { 
-#include <string.h> +18│   pthread_mutex_t mtx; 
- +19│   char text[256]; 
-struct { +20│ } item[5]; 
-  pthread_mutex_t mtx; +21│ 
-  char text[256]; +22│ int main(int argc, char **argv) { 
-} item[5]; +  … 
- +28│   for (intptr_t i = 1; i < 5; ++i) { 
-const char *arg0; +29│     pthread_t tid; 
- +30│     pthread_create(&tid, NULL, threadFunc, (void *)i); 
-void *threadFunc(intptr_t num) { +31│     pthread_detach(tid); 
-  char name[1024], cmd[1024]; +32│   } 
-  sprintf(name, "%s.pipe.%ld", arg0, num); +33│   threadFunc(0); 
-  sprintf(cmd, "rm -f %s; mkfifo %s", name, name); +34│ } 
-  system(cmd); +35│ 
-  FILE *myPipe = fopen(name, "r+"); +36│ void *threadFunc(void* numRaw) { 
- +37│   intptr_t num = (intptr_t) numRaw; 
-  while (1) { +38│   struct myIO win = openWin(num); 
-    char line[1024], nl; +  … 
-    fscanf(myPipe, "%1023[^\n]%c", line, &nl); +48│   while (1) { 
- +49│     fprintf(win.out, "> "); 
-    int argOne = atoi(line); +50│ 
-    if (argOne >= 5 || argOne < 0) +51│     char line[1024]; 
-      continue; +52│     fgets(line, 1024, win.in); 
- +53│     line[strlen(line)-1] = 0; 
-    char *argTwoTxt = strchr(line, ' '); +54│ 
- +55│     int argOne = atoi(line); 
-    if (!argTwoTxt) { +  … 
-      pthread_mutex_lock(&item[argOne].mtx); +61│     char *argTwoTxt = strchr(line, ' '); 
-      printf("T%ld reads %d as: %s\n", num, argOne, item[argOne].text); +62│ 
-      pthread_mutex_unlock(&item[argOne].mtx); +63│     if (!argTwoTxt) { 
-      continue; +65│       pthread_mutex_lock(&item[argOne].mtx); 
-    } +66│       fprintf(win.out, "T#%ld reads %d as: %s\n", num, argOne, item[argOne].text); 
- +67│       pthread_mutex_unlock(&item[argOne].mtx); 
-    argTwoTxt++; +68│       continue; 
-    char *e; +69│     } 
-    int argTwo = strtol(argTwoTxt, &e, 10); +70│ 
- +71│     argTwoTxt++; 
-    if (!*e && argTwo < 5 && argTwo >= 0 && argOne != argTwo) { +72│     char *e; 
-      pthread_mutex_lock(&item[argOne].mtx); +73│     int argTwo = strtol(argTwoTxt, &e, 10); 
-      pthread_mutex_lock(&item[argTwo].mtx); +74│ 
-      printf("T%ld copies %d to %d\n", num, argTwo, argOne); +75│     if (!*e && argTwo < 5 && argTwo >= 0 && argOne != argTwo) { 
-      memcpy(item[argOne].text, item[argTwo].text, sizeof(item[argOne].text)); +77│       pthread_mutex_lock(&item[argOne].mtx); 
-      pthread_mutex_unlock(&item[argTwo].mtx); +78│       pthread_mutex_lock(&item[argTwo].mtx); 
-      pthread_mutex_unlock(&item[argOne].mtx); +79│       fprintf(win.out, "T#%ld copies %d to %d\n", num, argTwo, argOne); 
-    } else { +80│       memcpy(item[argOne].text, item[argTwo].text, sizeof(item[argOne].text)); 
-      pthread_mutex_lock(&item[argOne].mtx); +81│       pthread_mutex_unlock(&item[argTwo].mtx); 
-      printf("T%ld assigns to %d the value: %s\n", num, argOne, argTwoTxt); +82│       pthread_mutex_unlock(&item[argOne].mtx); 
-      memset(item[argOne].text, 0, sizeof(item[argOne].text)); +83│     } else { 
-      strncpy(item[argOne].text, argTwoTxt, sizeof(item[argOne].text) - 1); +85│       pthread_mutex_lock(&item[argOne].mtx); 
-      pthread_mutex_unlock(&item[argOne].mtx); +86│       fprintf(win.out, "T#%ld assigns to %d the value: %s\n", num, argOne, argTwoTxt); 
-    } +87│       memset(item[argOne].text, 0, sizeof(item[argOne].text)); 
-  } +88│       strncpy(item[argOne].text, argTwoTxt, sizeof(item[argOne].text) - 1); 
-} +89│       pthread_mutex_unlock(&item[argOne].mtx); 
- +90│     } 
-int main(int argc, char **argv) { +91│   } 
-  arg0 = argv[0]; +92│ } 
- +  …
-  printf("To use this program, write to one of the %s.pipe.<thread_id> the " +
-         "following:\n" +
-         "  <num>             prints <text> from item <num>\n" +
-         "  <num> <text>      puts <text> to item <num>\n" +
-         "  <num1> <num2>     copies to item <num1> the text from item <num2>\n" +
-         "Valid pipe numbers are 0-4, valid item numbers are 0-4.", +
-         arg0); +
- +
-  for (int i = 0; i < 5; ++i) +
-    pthread_mutex_init(&item[i].mtx, NULL); +
- +
-  for (intptr_t i = 1; i < 5; ++i) { +
-    pthread_t tid; +
-    pthread_create(&tid, NULL, (void *(*)(void *))threadFunc, (void *)i); +
-    pthread_detach(tid); +
-  } +
-  threadFunc(0); +
-}+
 </code> </code>
-</small> 
 <html></div></html> <html></div></html>
  
Line 896: 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.1744833444.txt.gz · Last modified: (external edit)