This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
os_cp:threads [2024/04/17 23:28] jkonczak |
os_cp:threads [2025/04/25 13:55] (current) jkonczak [POSIX condition variables] |
||
---|---|---|---|
Line 69: | Line 69: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header:<br><code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header:<br><code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_create.html"></html> |
''int **pthread_create**(pthread_t *restrict //threadIdentifier//,'' \\ | ''int **pthread_create**(pthread_t *restrict //threadIdentifier//,'' \\ | ||
'' const pthread_attr_t *restrict //attr//,'' \\ | '' const pthread_attr_t *restrict //attr//,'' \\ | ||
Line 132: | Line 132: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_join.html"></html> |
''int **pthread_join**(pthread_t //thread//, void %%**%%//value_ptr//);'' | ''int **pthread_join**(pthread_t //thread//, void %%**%%//value_ptr//);'' | ||
<html></a></html> | <html></a></html> | ||
Line 209: | Line 209: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_detach.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_detach.html"></html> |
''int **pthread_detach**(pthread_t //thread//);'' | ''int **pthread_detach**(pthread_t //thread//);'' | ||
<html></a></html> | <html></a></html> | ||
Line 275: | Line 275: | ||
POSIX offers a mechanism called //cancellation//. That is, one can send to a | POSIX offers a mechanism called //cancellation//. That is, one can send to a | ||
thread a cancellation request using the | thread a cancellation request using the | ||
- | ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cancel.html|pthread_cancel]]'' | + | ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cancel.html|pthread_cancel]]'' |
function. Each thread can select is behaviour on receiving such request using the | function. Each thread can select is behaviour on receiving such request using the | ||
- | ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html|pthread_setcancelstate]]'' | + | ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setcancelstate.html|pthread_setcancelstate]]'' |
and | and | ||
- | ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html|pthread_setcanceltype]]'' | + | ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setcancelstate.html|pthread_setcanceltype]]'' |
functions. One may either allow or disallow cancalling a thread, and one may | functions. One may either allow or disallow cancalling a thread, and one may | ||
choose whether the cancallation should ouccur immediatly after a request, or | choose whether the cancallation should ouccur immediatly after a request, or | ||
at the next cancallation point. Cancellation points are the execution points | at the next cancallation point. Cancellation points are the execution points | ||
of several pthread functions, among which notably | of several pthread functions, among which notably | ||
- | ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html|pthread_testcancel]]'' | + | ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setcancelstate.html|pthread_testcancel]]'' |
is there just to this end. | is there just to this end. | ||
Once the thread complies to the cancellation request, it roughly does the same | Once the thread complies to the cancellation request, it roughly does the same | ||
Line 330: | Line 330: | ||
char text[1020]; | char text[1020]; | ||
- | void *updater(void *) { | + | void *updater(void * arg) { |
while (1) | while (1) | ||
for (char letter = 'a'; letter <= 'z'; ++letter) { | for (char letter = 'a'; letter <= 'z'; ++letter) { | ||
Line 343: | Line 343: | ||
pthread_t tid; | pthread_t tid; | ||
pthread_create(&tid, NULL, updater, NULL); | pthread_create(&tid, NULL, updater, NULL); | ||
- | while (getchar(), 1) | + | while (getchar() != EOF) |
printf("version: %llu\n text: %s\n", version, text); | printf("version: %llu\n text: %s\n", version, text); | ||
return 0; | return 0; | ||
Line 358: | Line 358: | ||
unsigned long long counter; | unsigned long long counter; | ||
- | void *incrementer(void *) { | + | void *incrementer(void * arg) { |
for (int i = 0; i < 1000; ++i) | for (int i = 0; i < 1000; ++i) | ||
counter++; | counter++; | ||
Line 374: | Line 374: | ||
} | } | ||
</code> | </code> | ||
+ | <html></div></html> | ||
+ | <html><div style="margin-top:-1.4em; line-height: 1em"></html> | ||
+ | <small>If the code above always returns the right answer, try to run it a million times: \\ | ||
+ | ''for X in `seq 1000000`; do RES=$(%%./%%//progname//); test "$RES" -ne 16000 && echo -e "\n$RES" && break || echo -n '.'; done'' | ||
+ | </small> | ||
<html></div></html> | <html></div></html> | ||
Line 396: | Line 401: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_init.html"></html> |
''pthread_mutex_t //mutex// = **PTHREAD_MUTEX_INITIALIZER**;'' | ''pthread_mutex_t //mutex// = **PTHREAD_MUTEX_INITIALIZER**;'' | ||
<html></a></html> | <html></a></html> | ||
Line 403: | Line 408: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_init.html"></html> |
''int **pthread_mutex_init**(pthread_mutex_t *restrict //mutex//,'' \\ | ''int **pthread_mutex_init**(pthread_mutex_t *restrict //mutex//,'' \\ | ||
'' const pthread_mutexattr_t *restrict //attr//)'' | '' const pthread_mutexattr_t *restrict //attr//)'' | ||
Line 415: | Line 420: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_init.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_init.html"></html> |
''int **pthread_mutexattr_init**(pthread_mutexattr_t *//attr//)'' | ''int **pthread_mutexattr_init**(pthread_mutexattr_t *//attr//)'' | ||
<html></a></html> | <html></a></html> | ||
\\ | \\ | ||
and finally set the attributes using corresponding functions: | and finally set the attributes using corresponding functions: | ||
- | * <html><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_settype.html"></html> ''int pthread_mutexattr_set**type**(pthread_mutexattr_t *//attr//, int //type//)''<html></a></html> sets mutex type (see below), | + | * <html><a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_settype.html"></html> ''int pthread_mutexattr_set**type**(pthread_mutexattr_t *//attr//, int //type//)''<html></a></html> sets mutex type (see below), |
- | * <small><html><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setpshared.html"></html>''int pthread_mutexattr_set**pshared**(pthread_mutexattr_t *//attr//, int //pshared//)''<html></a></html> allows sharing mutexes between processes (they need to reside in shared memory), </small> | + | * <small><html><a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_setpshared.html"></html>''int pthread_mutexattr_set**pshared**(pthread_mutexattr_t *//attr//, int //pshared//)''<html></a></html> allows sharing mutexes between processes (they need to reside in shared memory), </small> |
- | * <small><html><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html"></html>''int pthread_mutexattr_set**robust**(pthread_mutexattr_t *//attr//, int //robust//)''<html></a></html> when a thread holding a mutex terminated, a robust mutex will return appropriate error instead of waiting,</small> | + | * <small><html><a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_setrobust.html"></html>''int pthread_mutexattr_set**robust**(pthread_mutexattr_t *//attr//, int //robust//)''<html></a></html> when a thread holding a mutex terminated, a robust mutex will return appropriate error instead of waiting,</small> |
- | * <small>''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setprotocol.html|pthread_mutexattr_setprotocol]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setprioceiling.html|setprioceiling]]'' deal with priorities.</small> | + | * <small>''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_setprotocol.html|pthread_mutexattr_setprotocol]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutexattr_setprioceiling.html|setprioceiling]]'' deal with priorities.</small> |
The mutex type impacts what happens when a mutex that is already locked is | The mutex type impacts what happens when a mutex that is already locked is | ||
Line 447: | Line 452: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_lock.html"></html> |
''int **pthread_mutex_lock**(pthread_mutex_t *//mutex//)'' \\ | ''int **pthread_mutex_lock**(pthread_mutex_t *//mutex//)'' \\ | ||
''int pthread_mutex_trylock(pthread_mutex_t *//mutex//)'' | ''int pthread_mutex_trylock(pthread_mutex_t *//mutex//)'' | ||
<html></a></html> | <html></a></html> | ||
\\ | \\ | ||
- | <small><html><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html"></html> | + | <small><html><a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_timedlock.html"></html> |
''int pthread_mutex_timedlock(pthread_mutex_t *restrict //mutex//, const struct timespec *restrict //abstime//)'' | ''int pthread_mutex_timedlock(pthread_mutex_t *restrict //mutex//, const struct timespec *restrict //abstime//)'' | ||
<html></a></html></small> | <html></a></html></small> | ||
Line 467: | Line 472: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_lock.html"></html> |
''int **pthread_mutex_unlock**(pthread_mutex_t *//mutex//)'' | ''int **pthread_mutex_unlock**(pthread_mutex_t *//mutex//)'' | ||
<html></a></html> | <html></a></html> | ||
Line 613: | Line 618: | ||
\\ | \\ | ||
To create a rwlock one has to create a ''pthread_rwlock_t'' variable and initialize | To create a rwlock one has to create a ''pthread_rwlock_t'' variable and initialize | ||
- | it with either ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_init.html|PTHREAD_RWLOCK_INITIALIZER]]'' macro or ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_init.html|pthread_rwlock_init]]'' function. | + | it with either ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_init.html|PTHREAD_RWLOCK_INITIALIZER]]'' macro or ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_init.html|pthread_rwlock_init]]'' function. |
\\ | \\ | ||
A read-write lock can be locked with: | A read-write lock can be locked with: | ||
- | * ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html|pthread_rwlock_rdlock]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html|pthread_rwlock_tryrdlock]]'' in shared (read) mode, | + | * ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_rdlock.html|pthread_rwlock_rdlock]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_rdlock.html|pthread_rwlock_tryrdlock]]'' in shared (read) mode, |
- | * ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html|pthread_rwlock_wrlock]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html|pthread_rwlock_trywrlock]]'' in exclusive (write) mode. | + | * ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_wrlock.html|pthread_rwlock_wrlock]]'' and ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_wrlock.html|pthread_rwlock_trywrlock]]'' in exclusive (write) mode. |
<small>''pthread_rwlock_timedrdlock'' / ''pthread_rwlock_timedwrlock'' variants are also available.</small> | <small>''pthread_rwlock_timedrdlock'' / ''pthread_rwlock_timedwrlock'' variants are also available.</small> | ||
\\ | \\ | ||
- | To unlock a rwlock (locked in any mode), ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_unlock.html|pthread_rwlock_unlock]]'' is used. | + | To unlock a rwlock (locked in any mode), ''[[https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_rwlock_unlock.html|pthread_rwlock_unlock]]'' is used. |
Line 699: | 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 815: | Line 801: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Need header:<br><code>pthread.h</code></small></span> | <html><span style="float:right"><small>Need header:<br><code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_create.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_key_create.html"></html> |
''int **pthread_key_create**(pthread_key_t *//key//, void (*//destructor//)(void*))'' | ''int **pthread_key_create**(pthread_key_t *//key//, void (*//destructor//)(void*))'' | ||
<html></a></html> | <html></a></html> | ||
\\ | \\ | ||
- | <html><a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setspecific.html"></html> | + | <html><a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_setspecific.html"></html> |
''int **pthread_setspecific**(pthread_key_t //key//, const void *//value//)'' | ''int **pthread_setspecific**(pthread_key_t //key//, const void *//value//)'' | ||
\\ | \\ | ||
Line 891: | 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, | ||
Line 915: | Line 933: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_init.html"></html> |
''pthread_cond_t //cond// = **PTHREAD_COND_INITIALIZER**;'' | ''pthread_cond_t //cond// = **PTHREAD_COND_INITIALIZER**;'' | ||
<html></a></html> | <html></a></html> | ||
Line 923: | Line 941: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_init.html"></html> |
''int pthread_cond_init(pthread_cond_t *restrict //cond//, const pthread_condattr_t *restrict //attr//)'' | ''int pthread_cond_init(pthread_cond_t *restrict //cond//, const pthread_condattr_t *restrict //attr//)'' | ||
<html></a></html> | <html></a></html> | ||
Line 931: | Line 949: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_wait.html"></html> |
''int **pthread_cond_wait**(pthread_cond_t *restrict //cond//, pthread_mutex_t *restrict //mutex//)'' | ''int **pthread_cond_wait**(pthread_cond_t *restrict //cond//, pthread_mutex_t *restrict //mutex//)'' | ||
<html></a></html> | <html></a></html> | ||
Line 940: | Line 958: | ||
\\ | \\ | ||
<html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | <html><span style="float:right"><small>Needs header: <code>pthread.h</code></small></span> | ||
- | <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html"></html> | + | <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_broadcast.html"></html> |
''int **pthread_cond_signal**(pthread_cond_t *restrict //cond//)''\\ | ''int **pthread_cond_signal**(pthread_cond_t *restrict //cond//)''\\ | ||
''int **pthread_cond_broadcast**(pthread_cond_t *restrict //cond//)'' | ''int **pthread_cond_broadcast**(pthread_cond_t *restrict //cond//)'' |