Skocz do: nawigacji, wyszukiwania

MICLAB:Cpp11Threads


Środowisko i modele programowania

dr inż. Łukasz Szustak, Politechnika Częstochowska, IITiS
mgr inż. Kamil Halbiniak, Politechnika Częstochowska, IITiS



Standard C++ 11 Threads


Wielowątkowość w języku C++ pojawiła się w 2010 roku wraz z opublikowaniem standardu C++11. Standard ten oraz nowsze wersje definiują szeroką gammę bibliotek, które oferują różnego rodzaju mechanizmy umożliwiające zarządzanie wątkami. C++11 pozwala na tworzenie równoległych aplikacji dedykowanych zarówno dla nowoczesnych procesorów ogólnego przeznaczenia jak i akceleratorów obliczeniowych bazujących na architekturze Intel MIC. Standard ten nie wymaga instalacji dodatkowego oprogramowania platformy obliczeniowej (jak ma to miejsce w przypadku niektórych standardów). Wielowątkowość C++11 charakteryzuje podejście obiektowe. Wątki, mechanizmy synchronizacji oraz operacje atomowe reprezentowane są przez obiekty klas. Koncepcja zrównoleglenia w C++11 podobnie jak w przypadku wcześniej przedstawionych standardów programowania równoległego bazuje na modelu fork-join.


Nowy wątek uruchamiany jest wraz z utworzeniem obiektu klasy thread. Kod wykonywany przez wątek definiowany jest w osobnej funkcji określanej mianem funkcji inicjalizującej. Funkcja ta przypisywana jest do niego w trakcie jego tworzenia. Proces ten odbywa się to poprzez podanie funkcji jako argumentu konstruktora klasy reprezentującej wątek. C++11 dopuszcza możliwość przekazywania danych do wątków poprzez argumenty funkcji. Realizowane jest to poprzez dodatkowe argumenty konstruktora klasy reprezentującej wątek. Ich liczba musi być zgodna z liczbą argumentów zdefiniowaną w sygnaturze funkcji wykonywanej przez wątek. Standard nie narzuca ograniczeń zwią- zanych z funkcją wykonywaną przez wątek dzięki czemu ta sama funkcja może zostać wykorzystana do utworzenia wielu wątków.


Najprostszym sposobem definiowania kodu, który ma zostać wykonany przez wątek jest implementacja funkcji zgodnie z językiem programowania C++. Klasa thread współ pracuje również z obiektami typu wywoływalnego (callable). Dzięki temu programista może użyć obiektu klasy z przeciążonym operatorem wywołania jako funkcji, która ma zostać wykonana przez utworzony wątek. Tworzenie wątków przy użyciu obiektów klas odbywa się analogicznie, jak w przypadku tradycyjnych funkcji (do konstruktora klasy thread podawany jest obiekt klasy z przeciążonym operatorem wywołania).


Po uruchomieniu wątków istnieją one, aż do momentu jawnego wywołania funkcji join. Funkcja ta wstrzymuje wątek do momentu zakończenia obliczeń wykonywanych przez pozostałe wątki, a następnie zabija go. Wywołania funkcji na join na rzecz obiektu klasy thread automatycznie wywołuje jego destruktor. Uruchomienie większej liczby wątków wymaga wykorzystania tablic lub typów generycznych do przechowywania obiektów klasy thread. Przykład kodu źródłowego zrównoleglonego w standardzie C++11 przedstawiony został na Listingu 1.


#include <stdio.h>
#include "thread"
 
void DoWork(int threadId)
{
   printf("Hello World! Watek: %d\n", threadId);
}
 
int main()
{
   const int numThreads = 5;
   thread threads[numThreads];

   for(int i=0; i<numThreads; ++i)
   {
      threads[i] = thread(DoWork, i);
   }

   for(int i=0; i<numThreads; ++i)
   {
      threads[i].join();
   }

   return 0;
}
Listing 1. Zrównoleglenie w standardzie C++11


W C++11 wątki nie posiadają dyspozytora pętli. Podobnie jak w przypadku pThreads, za zrównoważenie obliczeń w pętli odpowiedzialny jest programista. Aplikacja zrównoleglona w standardzie C++11 posiada wątek główny, który wykonuje zadania sekwencyjnie, aż do momentu napotkania konstrukcji tworzącej nowe wątki. Standard przewiduje możliwość kilkukrotnego uruchamiania dowolnej liczby wątków o obrębie jednego programu. Pomiędzy obszarami równoległymi, aplikacja wykonywana jest przez wątek główny.


Standard C++11 poza możliwością tworzenia wątków posiada szereg różnych mechanizmów, do których zalicza się między innymi mutexy, monitory, zmienne warunkowe oraz operacje atomowe. W odróżnieniu do OpenMP oraz pThreads standard ten nie posiada mechanizmu affinity. Jednakże, możliwe jest zdefiniowanie sposobu przypisania wątków do logicznych rdzeni jednostki obliczeniowej przy pomocy dedykowanych do tego celu bibliotek (na przykład sched.h w systemach Linux). Wykorzystanie niektórych mechanizmów wymaga ich ręcznej implementacji przez programistę. Przykładem takiego mechanizmu może być bariera wykorzystywana do synchronizacji wątków w takcie wykonywania obliczeń.



< Standardy programowania równoległego - OpenMP

Standardy programowania równoległego - pThreads >