Narzędzia użytkownika

Narzędzia witryny


sk2:cpp11_threads

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Nowa wersja
Poprzednia wersja
sk2:cpp11_threads [2017/10/29 21:18]
jkonczak utworzono
sk2:cpp11_threads [2024/11/07 23:21] (aktualna)
jkonczak [[ekstra] Wątki w C++]
Linia 1: Linia 1:
-===== Wątki w C++11 ===== +===== [ekstra] ​Wątki w C++ ===== 
-Wraz ze standardem ​C++11 język ​C++ doczekał się obsługi wątków ​w bibliotece standardowej. \\ +Język ​C+''''​(od wersji ​C+''''​+11)  ma w bibliotece standardowej ​obsługę wątków. \\ 
-API do obsługi wątków ​jest identyczne ​z ''​boost::​thread'',​ z wyjątkiem obsługi przerywania wątków (''​thread::​interrupt()''​).+<​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>​
  
-Podsumowanie:​+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> <code cpp>
-#include <​thread>​ // właściwy plik nagłówkowy +t1.join(); // czeka na zakończenie wątku
-std::thread t; // tworzy pusty obiekt wątku. +
-t = thread(f); // tworzy nowy obiekt wątku w miejscu "​t",​ niszcząc poprzedni obiekt wątku  +
-               // i uruchamia w nim "​f"​ +
-// thread t2 = t; // kod NIEPOPRAWNY – wątków nie można kopiować +
-std::thread u(g, 1, 2, "​z"​) // tworzy obiekt wątku (u), tworzy nowy wątek programu i uruchamia +
-                            // "​g"​ z argumentami 1, 2 i "​z"​ +
-t.join(); // czeka na zakończenie wątku+
 // thread * w = new thread(h); delete w; // niepoprawne – jeśli zmienna reprezentująca wątek ​ // thread * w = new thread(h); delete w; // niepoprawne – jeśli zmienna reprezentująca wątek ​
                                          // ginie (''​~thread::​thread''​) przed zakończeniem wątku,                                          // ginie (''​~thread::​thread''​) przed zakończeniem wątku,
-                                         // to program jest abortowany+                                         // to program jest przerywany
 // Jeśli główny wątek (main) się zakończy, pozostałe są zabijane (zachowanie inne niż np. w Javie) // Jeśli główny wątek (main) się zakończy, pozostałe są zabijane (zachowanie inne niż np. w Javie)
-u.detach() // rozłącza wątek ze zmienną go reprezentującą. Można zmazać zmienną, wątek przeżyje.+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ć. std::​thread(i).detach();​ // tworzy nowy wątek bez deklaracji zmiennej która będzie go reprezentować.
 </​code>​ </​code>​
  
-<​html>​<small></​html+<​small>​ 
-W C++11 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>​
 <code cpp> <code cpp>
 thread_local int tid = i.fetch_add(1);​ thread_local int tid = i.fetch_add(1);​
Linia 30: Linia 90:
   * http://​en.cppreference.com/​w/​cpp/​atomic   * http://​en.cppreference.com/​w/​cpp/​atomic
   * http://​en.cppreference.com/​w/​cpp/​thread   * 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>​
 +++++
  
-<​html></​small></​html>​ +===== [ekstra] ​<​functional>​ w C++ ===== 
-===== <​functional>​ w C++11 ===== +<​small>​
-<​html>​<small><​small></​html>+
 Bardzo krótkie streszczenie:​ Bardzo krótkie streszczenie:​
 +<​html><​div style="​line-height:​105%;​margin-top:​-1.2em"></​div></​html>​
 <code cpp passingFuncs.cpp>​ <code cpp passingFuncs.cpp>​
 #include <​thread>​ #include <​thread>​
Linia 58: Linia 253:
  
 int main() { int main() {
- thread([]{cout << "​A"​ << endl;​}).join(); ​       // lambda – http://​en.cppreference.com/​w/​cpp/​language/​lambda + thread([]{cout << "​A"​ << endl;​}).join(); ​             // lambda – http://​en.cppreference.com/​w/​cpp/​language/​lambda  
- thread(b, '​B'​).join(); ​                         // "​zwykła"​ funkcja + thread(b, '​B'​).join(); ​                               // "​zwykła"​ funkcja 
- thread(objC).join(); ​                           // operator() + thread(objC).join(); ​                                 // operator() 
- thread(objC,​ '​D'​).join(); ​                      ​// operator() z argumentami + 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, 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 + thread(bind(&​E::​f,​ objE, _1), 5).join(); ​             // funkcja na rzecz obiektu z nieustalonym argumentem 
- function<​char(int)>​ funR(bind(&​E::​f,​&objE,_1)); // funkcja na rzecz obiektu wołanego przez referencję + 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+ function<​char(int)>​ funC(bind(&​E::​f,​ objE, _1));      // funkcja na rzecz obiektu w stanie z chwili tworzenia funcC
  objE.g(); ​                  // modyfikacja obiektu  objE.g(); ​                  // modyfikacja obiektu
  thread(funR,​ 0).join(); ​    // wywołanie zmodyfikowanego obiektu - funcR zna obiekt przez referencję  thread(funR,​ 0).join(); ​    // wywołanie zmodyfikowanego obiektu - funcR zna obiekt przez referencję
- thread(funC,​ 7).join(); ​    // wywołanie zmodyfikowanego obiektu - funcR zna obiekt przez wartość+ thread(funC,​ 7).join(); ​    // wywołanie zmodyfikowanego obiektu - funcC zna obiekt przez wartość
  return 0;  return 0;
 } }
 </​code>​ </​code>​
-<​html>​</small></​small></​html>+</​small>​
sk2/cpp11_threads.1509308312.txt.gz · ostatnio zmienione: 2017/10/29 21:18 przez jkonczak