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

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
sk2:cpp11_threads [2020/10/27 13:21]
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()''​).+<​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>​
 <code cpp threadHelloWorld.cpp>​ <code cpp threadHelloWorld.cpp>​
-#include <​thread>​ 
 #include <​cstdio>​ #include <​cstdio>​
-void funkcja(){ +#include <​thread>​ 
-    ​puts("​Hello ​world");+void funkcja(unsigned count, const char *argument) { 
 +    ​while (count--) 
 +        printf("​Hello ​%s\n", argument); 
 +    /* kod wykonywany w drugim wątku */
 } }
-int main(){ +int main() { 
-    std::thread t(funkcja);+    std::thread t(funkcja, 3, "​world"​); 
 +    /* kod wykonywany w pierwszym wątku */
     t.join();     t.join();
     return 0;     return 0;
 } }
 </​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:
 +<​html><​div style="​line-height:​105%;​margin-top:​-1.2em"></​div></​html>​
 <code cpp> <code cpp>
 std::thread t1(funkcja); ​  // tworzy obiekt '​t1',​ tworzy nowy wątek i uruchamia w nim '​funkcja()'​. std::thread t1(funkcja); ​  // tworzy obiekt '​t1',​ tworzy nowy wątek i uruchamia w nim '​funkcja()'​.
Linia 24: Linia 62:
                               tworzy nowy wątek i uruchamia w nim '​funkcja()'​ */                               tworzy nowy wątek i uruchamia w nim '​funkcja()'​ */
 // thread t3 = t2;         // kod NIEPOPRAWNY – wątków nie można kopiować // 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 std::thread t4(funkcja2,​ 1, 2, "​z"​);​ /* tworzy obiekt '​t4',​ tworzy nowy wątek programu
                               i uruchamia w nim '​funkcja2(1,​ 2, "​z"​)'​*/​                               i uruchamia w nim '​funkcja2(1,​ 2, "​z"​)'​*/​
Linia 29: Linia 69:
  
 Podsumowanie zajmowania się wątkiem: Podsumowanie zajmowania się wątkiem:
 +<​html><​div style="​line-height:​105%;​margin-top:​-1.2em"></​div></​html>​
 <code cpp> <code cpp>
 t1.join(); // czeka na zakończenie wątku t1.join(); // czeka na zakończenie wątku
Linia 39: Linia 80:
 </​code>​ </​code>​
  
-<​html>​<small></​html+<​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>​
 <code cpp> <code cpp>
 thread_local int tid = i.fetch_add(1);​ thread_local int tid = i.fetch_add(1);​
Linia 48: 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>​
-<​html>​</small></​html>+
  
 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 <​thread>​ 
 #include <​condition_variable>​ #include <​condition_variable>​
-#include <​mutex>​ 
 #include <​iostream>​ #include <​iostream>​
-#include <list>+#include <mutex> 
 +#include <​queue>​ 
 +#include <thread>
  
 std::mutex mtx; std::mutex mtx;
 std::​condition_variable cv; std::​condition_variable cv;
  
-std::list<​std::​string> ​slowa+std::queue<​std::​string> ​wiadomosci
-thread_local std::​string ​slowo;+thread_local std::​string ​wiadomosc;
  
-void consumer(){ +void producer() { 
-    while(true){+    while (true) { 
 +        std::cin >> wiadomosc;
         {         {
             std::​unique_lock<​std::​mutex>​ lock(mtx);             std::​unique_lock<​std::​mutex>​ lock(mtx);
-            ​cv.wait(lock, []{return slowa.size()!=0;}); +            ​wiadomosci.push(wiadomosc); 
-            ​slowo = slowa.front();​ +            ​cv.notify_one();
-            slowa.pop_front();+
         }         }
-        std::cout << slowo << std::endl; 
     }     }
 } }
  
-int main(){ +void consumer() { 
-    std::thread t(consumer);​ +    while (true) {
-    while(true) { +
-        std::cin >> slowo;+
         {         {
             std::​unique_lock<​std::​mutex>​ lock(mtx);             std::​unique_lock<​std::​mutex>​ lock(mtx);
-            ​slowa.push_back(slowo); +            ​cv.wait(lock, [] { return !wiadomosci.empty(); }); 
-            ​cv.notify_one();+            ​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>​ </​code>​
 +++++
  
 ===== [ekstra] <​functional>​ w C++ ===== ===== [ekstra] <​functional>​ w C++ =====
-<​html>​<small><​small></​html>+<​small>​
 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 116: 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.1603801266.txt.gz · ostatnio zmienione: 2020/10/27 13:21 przez jkonczak