3. Funkcje biblioteki czasu wykonywania
W tej sekcji opisano funkcje biblioteki środowiska uruchomieniowego OpenMP C i C++. Nagłówek <omp.h> deklaruje dwa typy, kilka funkcji, które mogą służyć do kontrolowania i wykonywania zapytań w środowisku wykonywania równoległego oraz funkcji blokowania, które mogą służyć do synchronizowania dostępu do danych.
Typ jest typem omp_lock_t
obiektu, który może reprezentować, że blokada jest dostępna lub że wątek jest właścicielem blokady. Te blokady są nazywane prostymi blokadami.
Typ jest typem omp_nest_lock_t
obiektu, który może reprezentować dostępną blokadę lub tożsamość wątku będącego właścicielem blokady i liczbę zagnieżdżeń (opisaną poniżej). Te blokady są określane jako zagnieżdżone blokady.
Funkcje biblioteki to funkcje zewnętrzne z połączeniem "C".
Opisy w tym rozdziale są podzielone na następujące tematy:
3.1 Funkcje środowiska wykonawczego
Funkcje opisane w tej sekcji mają wpływ na wątki, procesory i środowiska równoległe oraz monitorują je:
- omp_set_num_threads
- omp_get_num_threads
- omp_get_max_threads
- omp_get_thread_num
- omp_get_num_procs
- omp_in_parallel
- omp_set_dynamic
- omp_get_dynamic
- omp_set_nested
- omp_get_nested
3.1.1, funkcja omp_set_num_threads
Funkcja omp_set_num_threads
ustawia domyślną liczbę wątków do użycia w późniejszych regionach równoległych, które nie określają klauzuli num_threads
. Format jest następujący:
#include <omp.h>
void omp_set_num_threads(int num_threads);
Wartość parametru num_threads musi być dodatnią liczbą całkowitą. Jego efekt zależy od tego, czy jest włączona dynamiczna korekta liczby wątków. Aby uzyskać kompleksowy zestaw reguł dotyczących interakcji między omp_set_num_threads
funkcją a dynamiczną korektą wątków, zobacz sekcję 2.3.
Ta funkcja ma efekty opisane powyżej, gdy wywoływane z części programu, w której omp_in_parallel
funkcja zwraca zero. Jeśli jest wywoływana z części programu, w której omp_in_parallel
funkcja zwraca wartość niezerową, zachowanie tej funkcji jest niezdefiniowane.
To wywołanie ma pierwszeństwo przed zmienną OMP_NUM_THREADS
środowiskową. Wartość domyślna liczby wątków, które mogą być ustanawiane przez wywołanie omp_set_num_threads
lub przez ustawienie OMP_NUM_THREADS
zmiennej środowiskowej, można jawnie zastąpić jedną parallel
dyrektywą, określając klauzulę num_threads
.
Aby uzyskać więcej informacji, zobacz omp_set_dynamic.
Odwołania krzyżowe
- omp_set_dynamic, funkcja
- funkcja omp_get_dynamic
- zmienna środowiskowa OMP_NUM_THREADS
- num_threads, klauzula
3.1.2, funkcja omp_get_num_threads
Funkcja omp_get_num_threads
zwraca liczbę wątków aktualnie w zespole wykonujących region równoległy, z którego jest wywoływana. Format jest następujący:
#include <omp.h>
int omp_get_num_threads(void);
Klauzula num_threads
omp_set_num_threads
, funkcja i zmienna OMP_NUM_THREADS
środowiskowa kontrolują liczbę wątków w zespole.
Jeśli liczba wątków nie została jawnie ustawiona przez użytkownika, wartość domyślna to zdefiniowana przez implementację. Ta funkcja wiąże się z najbliższą dyrektywą otaczającą parallel
. W przypadku wywołania z części szeregowej programu lub z zagnieżdżonego regionu równoległego, ta funkcja zwraca wartość 1.
Aby uzyskać więcej informacji, zobacz omp_set_dynamic.
Odwołania krzyżowe
3.1.3, funkcja omp_get_max_threads
Funkcja omp_get_max_threads
zwraca liczbę całkowitą, która ma być co najmniej tak duża, jak liczba wątków, które byłyby używane do utworzenia zespołu, jeśli region równoległy bez num_threads
klauzuli miał być widoczny w tym momencie w kodzie. Format jest następujący:
#include <omp.h>
int omp_get_max_threads(void);
Następujące wyrażenie wyraża niższą granicę dla wartości :omp_get_max_threads
threads-used-for-next-team<=
omp_get_max_threads
Należy pamiętać, że jeśli inny region równoległy używa num_threads
klauzuli , aby zażądać określonej liczby wątków, gwarancja na dolnej granicy wyniku omp_get_max_threads
nie jest już przechowywana.
omp_get_max_threads
Wartość zwracana funkcji może służyć do dynamicznego przydzielania wystarczającego magazynu dla wszystkich wątków w zespole utworzonych w następnym regionie równoległym.
Odwołania krzyżowe
3.1.4, funkcja omp_get_thread_num
Funkcja omp_get_thread_num
zwraca numer wątku w swoim zespole wątku wykonującego funkcję. Numer wątku mieści się w przedziale od 0 do omp_get_num_threads()
-1 włącznie. Główny wątek zespołu to wątek 0.
Format jest następujący:
#include <omp.h>
int omp_get_thread_num(void);
W przypadku wywołania z regionu omp_get_thread_num
szeregowego zwraca wartość 0. Jeśli jest wywoływana z poziomu zagnieżdżonego regionu równoległego, która jest serializowana, ta funkcja zwraca wartość 0.
Odwołania krzyżowe
3.1.5, funkcja omp_get_num_procs
Funkcja omp_get_num_procs
zwraca liczbę procesorów, które są dostępne dla programu w momencie wywołania funkcji. Format jest następujący:
#include <omp.h>
int omp_get_num_procs(void);
3.1.6, funkcja omp_in_parallel
Funkcja omp_in_parallel
zwraca wartość niezerową, jeśli jest wywoływana w dynamicznym zakresie równoległego regionu wykonywanego równolegle. W przeciwnym razie zwraca wartość 0. Format jest następujący:
#include <omp.h>
int omp_in_parallel(void);
Ta funkcja zwraca wartość niezerową, gdy jest wywoływana z regionu wykonywanego równolegle, w tym zagnieżdżone regiony, które są serializowane.
3.1.7, funkcja omp_set_dynamic
Funkcja omp_set_dynamic
włącza lub wyłącza dynamiczną korektę liczby wątków dostępnych do wykonywania regionów równoległych. Format jest następujący:
#include <omp.h>
void omp_set_dynamic(int dynamic_threads);
Jeśli dynamic_threads daje w wyniku wartość niezerową, liczba wątków używanych do wykonywania nadchodzących regionów równoległych może zostać automatycznie skorygowana przez środowisko czasu wykonywania, aby najlepiej wykorzystać zasoby systemowe. W związku z tym liczba wątków określonych przez użytkownika jest maksymalną liczbą wątków. Liczba wątków w zespole wykonujących region równoległy pozostaje stała na czas trwania tego regionu równoległego i jest zgłaszana przez omp_get_num_threads
funkcję.
Jeśli dynamic_threads daje wartość 0, korekta dynamiczna jest wyłączona.
Ta funkcja ma efekty opisane powyżej, gdy wywoływane z części programu, w której omp_in_parallel
funkcja zwraca zero. Jeśli jest wywoływana z części programu, w której omp_in_parallel
funkcja zwraca wartość niezerową, zachowanie tej funkcji jest niezdefiniowane.
Wywołanie metody omp_set_dynamic
ma pierwszeństwo przed zmienną OMP_DYNAMIC
środowiskową.
Ustawieniem domyślnym dynamicznego dostosowania wątków jest zdefiniowana implementacja. W związku z tym kody użytkowników, które zależą od określonej liczby wątków do poprawnego wykonywania, powinny jawnie wyłączyć wątki dynamiczne. Implementacje nie są wymagane do zapewnienia możliwości dynamicznego dostosowywania liczby wątków, ale są one wymagane do zapewnienia interfejsu do obsługi przenośności na wszystkich platformach.
specyficzne dla firmy Microsoft
Bieżąca obsługa elementów omp_get_dynamic
i omp_set_dynamic
jest następująca:
Parametr omp_set_dynamic
wejściowy nie ma wpływu na zasady wątkowania i nie zmienia liczby wątków. omp_get_num_threads
Zawsze zwraca liczbę zdefiniowaną przez użytkownika, jeśli jest ustawiona lub domyślny numer wątku. W bieżącej implementacji firmy Microsoft wyłącza dynamiczne wątki, omp_set_dynamic(0)
aby można było ponownie użyć istniejącego zestawu wątków dla następującego regionu równoległego. omp_set_dynamic(1)
włącza wątki dynamiczne przez odrzucenie istniejącego zestawu wątków i utworzenie nowego zestawu dla nadchodzącego regionu równoległego. Liczba wątków w nowym zestawie jest taka sama jak stary zestaw i jest oparta na zwracanej wartości omp_get_num_threads
. W związku z tym, aby uzyskać najlepszą wydajność, użyj polecenia , aby ponownie użyć omp_set_dynamic(0)
istniejących wątków.
Odwołania krzyżowe
3.1.8, funkcja omp_get_dynamic
Funkcja omp_get_dynamic
zwraca wartość niezerową, jeśli jest włączona dynamiczna korekta wątków i zwraca wartość 0 w przeciwnym razie. Format jest następujący:
#include <omp.h>
int omp_get_dynamic(void);
Jeśli implementacja nie implementuje dynamicznej korekty liczby wątków, ta funkcja zawsze zwraca wartość 0. Aby uzyskać więcej informacji, zobacz omp_set_dynamic.
Odwołania krzyżowe
- Aby zapoznać się z opisem dynamicznego dostosowania wątku, zobacz omp_set_dynamic.
3.1.9, funkcja omp_set_nested
Funkcja omp_set_nested
włącza lub wyłącza zagnieżdżone równoległości. Format jest następujący:
#include <omp.h>
void omp_set_nested(int nested);
Jeśli zagnieżdżona wartość daje wartość 0, zagnieżdżona równoległość jest wyłączona, co jest wartością domyślną, a zagnieżdżone regiony równoległe są serializowane i wykonywane przez bieżący wątek. W przeciwnym razie jest włączona zagnieżdżona równoległość, a zagnieżdżone regiony mogą wdrażać dodatkowe wątki w celu utworzenia zagnieżdżonych zespołów.
Ta funkcja ma efekty opisane powyżej, gdy wywoływane z części programu, w której omp_in_parallel
funkcja zwraca zero. Jeśli jest wywoływana z części programu, w której omp_in_parallel
funkcja zwraca wartość niezerową, zachowanie tej funkcji jest niezdefiniowane.
To wywołanie ma pierwszeństwo przed zmienną OMP_NESTED
środowiskową.
Po włączeniu zagnieżdżonego równoległości liczba wątków używanych do wykonywania zagnieżdżonych regionów równoległych jest definiowana przez implementację. W związku z tym implementacje zgodne z protokołem OpenMP mogą serializować zagnieżdżone regiony równoległe nawet wtedy, gdy jest włączona zagnieżdżona równoległość.
Odwołania krzyżowe
3.1.10, funkcja omp_get_nested
Funkcja omp_get_nested
zwraca wartość niezerową, jeśli zagnieżdżona równoległość jest włączona i 0, jeśli jest wyłączona. Aby uzyskać więcej informacji na temat zagnieżdżonego równoległości, zobacz omp_set_nested. Format jest następujący:
#include <omp.h>
int omp_get_nested(void);
Jeśli implementacja nie implementuje zagnieżdżonego równoległości, ta funkcja zawsze zwraca wartość 0.
3.2 Funkcje blokowania
Funkcje opisane w tej sekcji manipulują blokadami używanymi do synchronizacji.
W przypadku następujących funkcji zmienna blokady musi mieć typ omp_lock_t
. Ta zmienna musi być dostępna tylko za pośrednictwem tych funkcji. Wszystkie funkcje blokady wymagają argumentu, który ma wskaźnik do omp_lock_t
typu.
- Funkcja omp_init_lock inicjuje prostą blokadę.
- Funkcja omp_destroy_lock usuwa prostą blokadę.
- Funkcja omp_set_lock czeka na udostępnienie prostej blokady.
- Funkcja omp_unset_lock zwalnia prostą blokadę.
- Funkcja omp_test_lock testuje prostą blokadę.
W przypadku następujących funkcji zmienna blokady musi mieć typ omp_nest_lock_t
. Ta zmienna musi być dostępna tylko za pośrednictwem tych funkcji. Wszystkie funkcje zagnieżdżenia blokady wymagają argumentu, który ma wskaźnik do omp_nest_lock_t
typu.
- Funkcja omp_init_nest_lock inicjuje zagnieżdżalną blokadę.
- Funkcja omp_destroy_nest_lock usuwa blokadę zagnieżdżalną.
- Funkcja omp_set_nest_lock czeka na udostępnienie zagnieżdżonej blokady.
- Funkcja omp_unset_nest_lock zwalnia blokadę zagnieżdżalną.
- Funkcja omp_test_nest_lock testuje blokadę zagnieżdżalną.
Funkcje blokady OpenMP uzyskują dostęp do zmiennej blokady w taki sposób, że zawsze odczytują i aktualizują najbardziej bieżącą wartość zmiennej blokady. W związku z tym nie jest konieczne, aby program OpenMP zawierał jawne flush
dyrektywy, aby upewnić się, że wartość zmiennej blokady jest spójna między różnymi wątkami. (Może być konieczne flush
wprowadzenie dyrektyw, aby wartości innych zmiennych były spójne).
Funkcje omp_init_lock i omp_init_nest_lock 3.2.1
Te funkcje zapewniają jedyny sposób inicjowania blokady. Każda funkcja inicjuje blokadę skojarzona z blokadą parametru do użycia w nadchodzących wywołaniach. Format jest następujący:
#include <omp.h>
void omp_init_lock(omp_lock_t *lock);
void omp_init_nest_lock(omp_nest_lock_t *lock);
Stan początkowy jest odblokowany (czyli żaden wątek nie jest właścicielem blokady). W przypadku zagnieżdżonej blokady początkowa liczba zagnieżdżeń wynosi zero. Nie jest zgodne, aby wywołać jedną z tych procedur ze zmienną blokady, która została już zainicjowana.
3.2.2 funkcje omp_destroy_lock i omp_destroy_nest_lock
Te funkcje zapewniają, że blokada zmiennej blokady jest niezainicjowana. Format jest następujący:
#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock);
void omp_destroy_nest_lock(omp_nest_lock_t *lock);
Nie jest zgodne, aby wywołać jedną z tych procedur ze zmienną blokady, która jest niezainicjowana lub odblokowana.
Funkcje omp_set_lock i omp_set_nest_lock 3.2.3
Każda z tych funkcji blokuje wątek wykonujący funkcję, dopóki określona blokada nie będzie dostępna, a następnie ustawi blokadę. Prosta blokada jest dostępna, jeśli jest odblokowana. Blokada zagnieżdżona jest dostępna, jeśli jest odblokowana lub czy jest już własnością wątku wykonującego funkcję. Format jest następujący:
#include <omp.h>
void omp_set_lock(omp_lock_t *lock);
void omp_set_nest_lock(omp_nest_lock_t *lock);
W przypadku prostej blokady argument omp_set_lock
funkcji musi wskazywać zainicjowaną zmienną blokady. Własność blokady jest przyznawana wątkowi wykonującemu funkcję.
W przypadku zagnieżdżonej blokady argument omp_set_nest_lock
funkcji musi wskazywać zainicjowaną zmienną blokady. Liczba zagnieżdżeń jest zwiększana, a wątek jest udzielany lub utrzymuje własność blokady.
Funkcje omp_unset_lock i omp_unset_nest_lock 3.2.4
Te funkcje zapewniają środki zwalniania własności blokady. Format jest następujący:
#include <omp.h>
void omp_unset_lock(omp_lock_t *lock);
void omp_unset_nest_lock(omp_nest_lock_t *lock);
Argument dla każdej z tych funkcji musi wskazywać zainicjowaną zmienną blokady należącą do wątku wykonującego funkcję. Zachowanie jest niezdefiniowane, jeśli wątek nie jest właścicielem tej blokady.
W przypadku prostej blokady omp_unset_lock
funkcja zwalnia wątek wykonujący funkcję z własności blokady.
W przypadku zagnieżdżonej blokady funkcja dekrementuje liczbę zagnieżdżeń i zwalnia wątek wykonujący funkcję z własności blokady, omp_unset_nest_lock
jeśli wynikowa liczba wynosi zero.
Funkcje omp_test_lock i omp_test_nest_lock 3.2.5
Te funkcje próbują ustawić blokadę, ale nie blokują wykonywania wątku. Format jest następujący:
#include <omp.h>
int omp_test_lock(omp_lock_t *lock);
int omp_test_nest_lock(omp_nest_lock_t *lock);
Argument musi wskazywać zainicjowaną zmienną blokady. Te funkcje próbują ustawić blokadę w taki sam sposób jak omp_set_lock
i omp_set_nest_lock
, z tą różnicą, że nie blokują wykonywania wątku.
W przypadku prostej blokady omp_test_lock
funkcja zwraca wartość niezerową, jeśli blokada została pomyślnie ustawiona. W przeciwnym razie zwraca zero.
W przypadku zagnieżdżonej blokady omp_test_nest_lock
funkcja zwraca nową liczbę zagnieżdżeń, jeśli blokada została pomyślnie ustawiona. W przeciwnym razie zwraca zero.
3.3 Procedury chronometrażu
Funkcje opisane w tej sekcji obsługują przenośny zegar zegara:
- Funkcja omp_get_wtime zwraca czas zegara ściany.
- Funkcja omp_get_wtick zwraca sekundy między kolejnymi znacznikami zegara.
3.3.1, funkcja omp_get_wtime
Funkcja omp_get_wtime
zwraca wartość zmiennoprzecinkową o podwójnej precyzji równą czasowi zegara ściennego upłynął w sekundach od czasu "czasu w przeszłości". Rzeczywisty "czas w przeszłości" jest dowolny, ale gwarantowane jest, aby nie zmieniać się podczas wykonywania programu aplikacji. Format jest następujący:
#include <omp.h>
double omp_get_wtime(void);
Przewiduje się, że funkcja będzie używana do mierzenia czasu, który upłynął, jak pokazano w poniższym przykładzie:
double start;
double end;
start = omp_get_wtime();
... work to be timed ...
end = omp_get_wtime();
printf_s("Work took %f sec. time.\n", end-start);
Zwracane czasy to "godziny na wątek", co oznacza, że nie muszą być globalnie spójne we wszystkich wątkach uczestniczących w aplikacji.
3.3.2, funkcja omp_get_wtick
Funkcja omp_get_wtick
zwraca wartość zmiennoprzecinkową o podwójnej precyzji równą liczbie sekund między kolejnymi znacznikami zegara. Format jest następujący:
#include <omp.h>
double omp_get_wtick(void);