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/16 21:57]
jkonczak
os_cp:threads [2025/04/25 13:55] (current)
jkonczak [POSIX condition variables]
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(&tidNULLthreadFunc(void *)i); 
-void *threadFunc(intptr_t ​num) { +31│     ​pthread_detach(tid); 
-  char name[1024], cmd[1024]+32│   } 
-  ​sprintf(name"​%s.pipe.%ld"​arg0num); +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_tnumRaw
-  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(line1024win.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: 2025/04/16 21:57 by jkonczak