przejście do zawartości
Jan Kończak
Narzędzia użytkownika
Zaloguj
Narzędzia witryny
Narzędzia
Pokaż stronę
Poprzednie wersje
Odnośniki
Ostatnie zmiany
Menadżer multimediów
Indeks
Zaloguj
Ostatnie zmiany
Menadżer multimediów
Indeks
Jesteś tutaj:
start
»
sk2
»
cpp11_threads
sk2:cpp11_threads
Ta strona jest tylko do odczytu. Możesz wyświetlić źródła tej strony ale nie możesz ich zmienić.
===== [ekstra] Wątki w C++ ===== Język C+''''+ (od wersji C+''''+11) ma w bibliotece standardowej obsługę wątków. \\ <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: <html><div style="line-height:105%;margin-top:-1.2em"></div></html> <code cpp threadHelloWorld.cpp> #include <cstdio> #include <thread> void funkcja(unsigned count, const char *argument) { while (count--) printf("Hello %s\n", argument); /* kod wykonywany w drugim wątku */ } int main() { std::thread t(funkcja, 3, "world"); /* kod wykonywany w pierwszym wątku */ t.join(); return 0; } </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: <html><div style="line-height:105%;margin-top:-1.2em"></div></html> <code cpp> std::thread t1(funkcja); // tworzy obiekt 't1', tworzy nowy wątek i uruchamia w nim 'funkcja()'. std::thread t2; // tworzy pusty obiekt 't2'. t2 = std::thread(funkcja); /* tworzy nowy obiekt w miejscu "t2", niszczy poprzedni obiekt, tworzy nowy wątek i uruchamia w nim 'funkcja()' */ // thread t3 = t2; // kod NIEPOPRAWNY – wątków nie można kopiować thread t3 = std::move(t2); // ale wątki można przesuwać std::thread t4(funkcja2, 1, 2, "z"); /* tworzy obiekt 't4', tworzy nowy wątek programu i uruchamia w nim 'funkcja2(1, 2, "z")'*/ </code> Podsumowanie zajmowania się wątkiem: <html><div style="line-height:105%;margin-top:-1.2em"></div></html> <code cpp> t1.join(); // czeka na zakończenie wątku // thread * w = new thread(h); delete w; // niepoprawne – jeśli zmienna reprezentująca wątek // ginie (''~thread::thread'') przed zakończeniem wątku, // to program jest przerywany // Jeśli główny wątek (main) się zakończy, pozostałe są zabijane (zachowanie inne niż np. w Javie) t2.detach() // rozłącza wątek ze zmienną go reprezentującą. Można zmazać zmienną, wątek przeżyje. std::thread(i).detach(); // tworzy nowy wątek bez deklaracji zmiennej która będzie go reprezentować. </code> <small> 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> <code cpp> thread_local int tid = i.fetch_add(1); </code> Ponadto, dodano API do zamków, zmiennych warunkowych, zmiennych atomowych i futures * http://en.cppreference.com/w/cpp/atomic * http://en.cppreference.com/w/cpp/thread </small> 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> #include <condition_variable> #include <iostream> #include <mutex> #include <queue> #include <thread> std::mutex mtx; std::condition_variable cv; std::queue<std::string> wiadomosci; thread_local std::string wiadomosc; void producer() { while (true) { std::cin >> wiadomosc; { std::unique_lock<std::mutex> lock(mtx); wiadomosci.push(wiadomosc); cv.notify_one(); } } } void consumer() { while (true) { { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [] { return !wiadomosci.empty(); }); wiadomosc = wiadomosci.front(); wiadomosci.pop(); } std::cout << wiadomosc << std::endl; } } int main() { std::thread t(consumer); producer(); } </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++ ===== <small> Bardzo krótkie streszczenie: <html><div style="line-height:105%;margin-top:-1.2em"></div></html> <code cpp passingFuncs.cpp> #include <thread> #include <iostream> #include <functional> using namespace std; using namespace std::placeholders; void b(char c){ cout << c << endl;} class C{ public: void operator()() {cout << 'C' << endl;} void operator()(char c) {cout << c << endl;} } objC; class E{ const char * t_ = "ABCDEFGH"; public: char f(int i){ cout << t_[i] << endl; return t_[i];} void g(){t_="G";} } objE; int main() { thread([]{cout << "A" << endl;}).join(); // lambda – http://en.cppreference.com/w/cpp/language/lambda thread(b, 'B').join(); // "zwykła" funkcja thread(objC).join(); // operator() thread(objC, 'D').join(); // operator() z argumentami thread(bind(&E::f, objE, 4)).join(); // funkcja na rzecz obiektu z ustalonym argumentem (currying) thread(bind(&E::f, objE, _1), 5).join(); // funkcja na rzecz obiektu z nieustalonym argumentem function<char(int)> funR(bind(&E::f, ref(objE), _1)); // funkcja na rzecz obiektu wołanego przez referencję function<char(int)> funC(bind(&E::f, objE, _1)); // funkcja na rzecz obiektu w stanie z chwili tworzenia funcC objE.g(); // modyfikacja obiektu thread(funR, 0).join(); // wywołanie zmodyfikowanego obiektu - funcR zna obiekt przez referencję thread(funC, 7).join(); // wywołanie zmodyfikowanego obiektu - funcC zna obiekt przez wartość return 0; } </code> </small>
sk2/cpp11_threads.txt
· ostatnio zmienione: 2024/11/07 23:21 przez
jkonczak
Narzędzia strony
Pokaż stronę
Poprzednie wersje
Odnośniki
Złóż / rozłóż wszystko
Do góry