Różnice między wybraną wersją a wersją aktualną.
Both sides previous revision Poprzednia wersja Nowa wersja | Poprzednia wersja | ||
sk2:cpp11_threads [2024/11/07 14:31] jkonczak |
sk2:cpp11_threads [2024/11/07 23:21] (aktualna) jkonczak [[ekstra] Wątki w C++] |
||
---|---|---|---|
Linia 1: | Linia 1: | ||
===== [ekstra] Wątki w C++ ===== | ===== [ekstra] Wątki w C++ ===== | ||
Język C+''''+ (od wersji C+''''+11) ma w bibliotece standardowej obsługę wątków. \\ | Język C+''''+ (od wersji C+''''+11) ma w bibliotece standardowej obsługę wątków. \\ | ||
- | API do obsługi wątków w C+''''+ zostało przeniesione z ''boost::thread'', z wyjątkiem obsługi przerywania wątków (''thread::interrupt()'')((W C+''''+20 pojawiła się klasa ''std::jthread'' która pozwala zasygnalizować wątkowi że powinien się przerwać, ale wywołanie ''request_stop'' __nie__ przerywa wywołań systemowych (np. ''read''). )). | + | <small>API do obsługi wątków w C+''''+ zostało przeniesione z ''boost::thread'', z wyjątkiem obsługi przerywania wątków (''thread::interrupt()'')((W C+''''+20 pojawiła się klasa ''std::jthread'' która pozwala zasygnalizować wątkowi że powinien się przerwać, ale wywołanie ''request_stop'' __nie__ przerywa wywołań systemowych (np. ''read''). )).</small> |
Przykład prostego programu: | Przykład prostego programu: | ||
<html><div style="line-height:105%;margin-top:-1.2em"></div></html> | <html><div style="line-height:105%;margin-top:-1.2em"></div></html> | ||
<code cpp threadHelloWorld.cpp> | <code cpp threadHelloWorld.cpp> | ||
- | #include <thread> | ||
#include <cstdio> | #include <cstdio> | ||
- | void funkcja(const char * argument){ | + | #include <thread> |
- | printf("Hello %s\n", argument); | + | void funkcja(unsigned count, const char *argument) { |
+ | while (count--) | ||
+ | printf("Hello %s\n", argument); | ||
/* kod wykonywany w drugim wątku */ | /* kod wykonywany w drugim wątku */ | ||
} | } | ||
- | int main(){ | + | int main() { |
- | std::thread t(funkcja, "world"); | + | std::thread t(funkcja, 3, "world"); |
/* kod wykonywany w pierwszym wątku */ | /* kod wykonywany w pierwszym wątku */ | ||
t.join(); | t.join(); | ||
Linia 19: | Linia 20: | ||
} | } | ||
</code> | </code> | ||
+ | <html><div style="margin-top:-1.2em;margin-bottom:-1.2em"></div></html> | ||
+ | ++++ Odpowiednik kodu w C używający pthreads| | ||
+ | <html><div style="line-height:105%;margin-top:-3em"></div></html> | ||
+ | <code cpp threadHelloWorld.c> | ||
+ | #include <pthread.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | struct funkcja_argumenty{ | ||
+ | unsigned count; | ||
+ | const char * argument; | ||
+ | }; | ||
+ | |||
+ | void * funkcja(void * rawArgs){ | ||
+ | struct funkcja_argumenty *args = rawArgs; | ||
+ | while(args->count--) | ||
+ | printf("Hello %s\n", args->argument); | ||
+ | free(rawArgs); | ||
+ | /* kod wykonywany w drugim wątku */ | ||
+ | return NULL; | ||
+ | } | ||
+ | int main(void){ | ||
+ | pthread_t tid; | ||
+ | struct funkcja_argumenty *args = malloc(sizeof(struct funkcja_argumenty)); | ||
+ | args->count = 3; | ||
+ | args->argument = "world"; | ||
+ | pthread_create(&tid, NULL, funkcja, args); | ||
+ | /* kod wykonywany w pierwszym wątku */ | ||
+ | pthread_join(tid, NULL); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | ++++ | ||
Podsumowanie tworzenia wątków: | Podsumowanie tworzenia wątków: | ||
Linia 47: | Linia 81: | ||
<small> | <small> | ||
- | W C++ ustandaryzowano też zmienne lokalne dla wątku – w deklaracji zmiennej wystarczy dodać słowo kluczowe ''thread_local'', np: | + | W C+%%%%+ ustandaryzowano też zmienne lokalne dla wątku – w deklaracji zmiennej wystarczy dodać słowo kluczowe ''thread_local'', np: |
<html><div style="line-height:105%;margin-top:-1.2em"></div></html> | <html><div style="line-height:105%;margin-top:-1.2em"></div></html> | ||
<code cpp> | <code cpp> | ||
Linia 59: | Linia 93: | ||
Przykład synchronizacji między wątkami (producent-konsument): | Przykład synchronizacji między wątkami (producent-konsument): | ||
+ | <html><div style="line-height:105%;margin-top:-1.2em"></div></html> | ||
<code cpp condVarHelloWorld.cpp> | <code cpp condVarHelloWorld.cpp> | ||
#include <condition_variable> | #include <condition_variable> | ||
Linia 100: | Linia 135: | ||
} | } | ||
</code> | </code> | ||
+ | <html><div style="margin-top:-1.2em;margin-bottom:-1.2em"></div></html> | ||
+ | ++++ Odpowiednik kodu w C używający pthreads| | ||
+ | <html><div style="line-height:105%;margin-top:-3em"></div></html> | ||
+ | <code cpp condVarHelloWorld.c> | ||
+ | #include <pthread.h> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | struct dumbQueue *msgQueue; | ||
+ | |||
+ | struct dumbQueue* dumbQueue_create (void); | ||
+ | void dumbQueue_push (struct dumbQueue *q, void *element); | ||
+ | void* dumbQueue_pop (struct dumbQueue *q); | ||
+ | int dumbQueue_isEmpty(struct dumbQueue *q); | ||
+ | |||
+ | pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; | ||
+ | pthread_cond_t cv = PTHREAD_COND_INITIALIZER; | ||
+ | |||
+ | _Thread_local char *msg; | ||
+ | |||
+ | void producer(void) { | ||
+ | while (1) { | ||
+ | msg = malloc(255); | ||
+ | scanf("%*[\n]"); | ||
+ | scanf("%254[^\n]", msg); | ||
+ | { | ||
+ | pthread_mutex_lock(&mtx); | ||
+ | dumbQueue_push(msgQueue, msg); | ||
+ | pthread_cond_signal(&cv); | ||
+ | pthread_mutex_unlock(&mtx); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void *consumer(void *_) { | ||
+ | while (1) { | ||
+ | { | ||
+ | pthread_mutex_lock(&mtx); | ||
+ | while (dumbQueue_isEmpty(msgQueue)) | ||
+ | pthread_cond_wait(&cv, &mtx); | ||
+ | msg = dumbQueue_pop(msgQueue); | ||
+ | pthread_mutex_unlock(&mtx); | ||
+ | } | ||
+ | printf("%s\n", msg); | ||
+ | free(msg); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | int main(void) { | ||
+ | msgQueue = dumbQueue_create(); | ||
+ | pthread_t tid; | ||
+ | pthread_create(&tid, NULL, consumer, NULL); | ||
+ | producer(); | ||
+ | } | ||
+ | |||
+ | /*****/ struct dumbQueue { | ||
+ | /* T */ struct dumbQueue_e { | ||
+ | /* h */ void *element; | ||
+ | /* i */ struct dumbQueue_e *next; | ||
+ | /* s */ } *head, *tail; | ||
+ | /* */ }; | ||
+ | /* i */ | ||
+ | /* s */ struct dumbQueue *dumbQueue_create(void) { | ||
+ | /* */ struct dumbQueue *q = malloc(sizeof(struct dumbQueue)); | ||
+ | /* j */ q->head = malloc(sizeof(struct dumbQueue_e)); | ||
+ | /* u */ q->head->next = NULL; | ||
+ | /* s */ q->tail = q->head; | ||
+ | /* t */ return q; | ||
+ | /* */ } | ||
+ | /* a */ | ||
+ | /* */ void dumbQueue_push(struct dumbQueue *q, void *element) { | ||
+ | /* d */ q->tail->next = malloc(sizeof(struct dumbQueue_e)); | ||
+ | /* u */ q->tail = q->tail->next; | ||
+ | /* m */ q->tail->next = NULL; | ||
+ | /* b */ q->tail->element = element; | ||
+ | /* */ } | ||
+ | /* q */ | ||
+ | /* u */ void *dumbQueue_pop(struct dumbQueue *q) { | ||
+ | /* e */ struct dumbQueue_e *next = q->head->next; | ||
+ | /* u */ free(q->head); | ||
+ | /* e */ q->head = next; | ||
+ | /* */ return q->head->element; | ||
+ | /* i */ } | ||
+ | /* m */ | ||
+ | /* p */ int dumbQueue_isEmpty(struct dumbQueue *q) { | ||
+ | /* l */ return q->head->next == NULL; | ||
+ | /*****/ } | ||
+ | </code> | ||
+ | ++++ | ||
===== [ekstra] <functional> w C++ ===== | ===== [ekstra] <functional> w C++ ===== |