3. Funzioni della libreria di runtime
Questa sezione descrive le funzioni della libreria di runtime C e C++ OpenMP. L'intestazione <omp.h> dichiara due tipi, diverse funzioni che possono essere usate per controllare ed eseguire query sull'ambiente di esecuzione parallela e funzioni di blocco che possono essere usate per sincronizzare l'accesso ai dati.
Il tipo è un tipo omp_lock_t
di oggetto in grado di rappresentare che è disponibile un blocco o che un thread possiede un blocco. Questi blocchi sono definiti semplici blocchi.
Il tipo è un tipo omp_nest_lock_t
di oggetto in grado di rappresentare che è disponibile un blocco o sia l'identità del thread proprietario del blocco che un conteggio annidamento (descritto di seguito). Questi blocchi sono detti blocchi annidabili.
Le funzioni di libreria sono funzioni esterne con collegamento "C".
Le descrizioni di questo capitolo sono suddivise negli argomenti seguenti:
3.1 Funzioni dell'ambiente di esecuzione
Le funzioni descritte in questa sezione influiscono sui thread, sui processori e sull'ambiente parallelo:
- 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 funzione omp_set_num_threads
La omp_set_num_threads
funzione imposta il numero predefinito di thread da usare per aree parallele successive che non specificano una num_threads
clausola. Il formato è il seguente:
#include <omp.h>
void omp_set_num_threads(int num_threads);
Il valore del parametro num_threads deve essere un numero intero positivo. L'effetto dipende dal fatto che la regolazione dinamica del numero di thread sia abilitata. Per un set completo di regole sull'interazione tra la funzione e la omp_set_num_threads
regolazione dinamica dei thread, vedere la sezione 2.3.
Questa funzione ha gli effetti descritti in precedenza quando viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce zero. Se viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce un valore diverso da zero, il comportamento di questa funzione non è definito.
Questa chiamata ha la precedenza sulla variabile di OMP_NUM_THREADS
ambiente. Il valore predefinito per il numero di thread, che può essere stabilito chiamando omp_set_num_threads
o impostando la OMP_NUM_THREADS
variabile di ambiente, può essere sottoposto a override in modo esplicito su una singola parallel
direttiva specificando la num_threads
clausola .
Per altre informazioni, vedere omp_set_dynamic.
Riferimenti incrociati
- funzione omp_set_dynamic
- funzione omp_get_dynamic
- OMP_NUM_THREADS variabile di ambiente
- clausola num_threads
3.1.2 funzione omp_get_num_threads
La omp_get_num_threads
funzione restituisce il numero di thread attualmente presenti nel team che esegue l'area parallela da cui viene chiamata. Il formato è il seguente:
#include <omp.h>
int omp_get_num_threads(void);
La num_threads
clausola, la omp_set_num_threads
funzione e la OMP_NUM_THREADS
variabile di ambiente controllano il numero di thread in un team.
Se il numero di thread non è stato impostato in modo esplicito dall'utente, il valore predefinito è definito dall'implementazione. Questa funzione viene associata alla direttiva di inclusione parallel
più vicina. Se viene chiamato da una parte seriale di un programma o da un'area parallela annidata serializzata, questa funzione restituisce 1.
Per altre informazioni, vedere omp_set_dynamic.
Riferimenti incrociati
3.1.3 funzione omp_get_max_threads
La omp_get_max_threads
funzione restituisce un numero intero garantito che sia almeno pari al numero di thread che verrebbero usati per formare un team se un'area parallela senza una num_threads
clausola dovesse essere visualizzata in quel punto del codice. Il formato è il seguente:
#include <omp.h>
int omp_get_max_threads(void);
Di seguito viene espresso un limite inferiore sul valore di omp_get_max_threads
:
threads-used-for-next-team<=
omp_get_max_threads
Si noti che se un'altra area parallela usa la num_threads
clausola per richiedere un numero specifico di thread, la garanzia sul limite inferiore del risultato di omp_get_max_threads
non contiene più.
Il omp_get_max_threads
valore restituito della funzione può essere usato per allocare in modo dinamico spazio di archiviazione sufficiente per tutti i thread del team formato nella successiva area parallela.
Riferimenti incrociati
3.1.4 funzione omp_get_thread_num
La omp_get_thread_num
funzione restituisce il numero di thread, all'interno del relativo team, del thread che esegue la funzione. Il numero di thread è compreso tra 0 e omp_get_num_threads()
-1, inclusi. Il thread master del team è thread 0.
Il formato è il seguente:
#include <omp.h>
int omp_get_thread_num(void);
Se viene chiamato da un'area seriale, omp_get_thread_num
restituisce 0. Se viene chiamato dall'interno di un'area parallela annidata serializzata, questa funzione restituisce 0.
Riferimenti incrociati
3.1.5 funzione omp_get_num_procs
La omp_get_num_procs
funzione restituisce il numero di processori disponibili per il programma al momento della chiamata della funzione. Il formato è il seguente:
#include <omp.h>
int omp_get_num_procs(void);
3.1.6 funzione omp_in_parallel
La omp_in_parallel
funzione restituisce un valore diverso da zero se viene chiamato all'interno dell'extent dinamico di un'area parallela in esecuzione in parallelo; in caso contrario, restituisce 0. Il formato è il seguente:
#include <omp.h>
int omp_in_parallel(void);
Questa funzione restituisce un valore diverso da zero quando viene chiamato dall'interno di un'area in esecuzione in parallelo, incluse le aree annidate serializzate.
3.1.7 omp_set_dynamic funzione
La omp_set_dynamic
funzione abilita o disabilita la regolazione dinamica del numero di thread disponibili per l'esecuzione di aree parallele. Il formato è il seguente:
#include <omp.h>
void omp_set_dynamic(int dynamic_threads);
Se dynamic_threads restituisce un valore diverso da zero, il numero di thread usati per l'esecuzione di aree parallele future può essere modificato automaticamente dall'ambiente di runtime per usare al meglio le risorse di sistema. Di conseguenza, il numero di thread specificati dall'utente è il numero massimo di thread. Il numero di thread nel team che esegue un'area parallela rimane fisso per la durata dell'area parallela e viene segnalato dalla omp_get_num_threads
funzione .
Se dynamic_threads restituisce 0, la regolazione dinamica è disabilitata.
Questa funzione ha gli effetti descritti in precedenza quando viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce zero. Se viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce un valore diverso da zero, il comportamento di questa funzione non è definito.
Una chiamata a omp_set_dynamic
ha la precedenza sulla OMP_DYNAMIC
variabile di ambiente.
Il valore predefinito per la regolazione dinamica dei thread è definito dall'implementazione. Di conseguenza, i codici utente che dipendono da un numero specifico di thread per l'esecuzione corretta devono disabilitare in modo esplicito i thread dinamici. Le implementazioni non sono necessarie per fornire la possibilità di regolare dinamicamente il numero di thread, ma sono necessarie per fornire l'interfaccia per supportare la portabilità in tutte le piattaforme.
Specifico di Microsoft
Il supporto corrente di omp_get_dynamic
e omp_set_dynamic
è il seguente:
Il parametro di input di omp_set_dynamic
non influisce sui criteri di threading e non modifica il numero di thread. omp_get_num_threads
restituisce sempre il numero definito dall'utente, se impostato o il numero di thread predefinito. Nell'implementazione omp_set_dynamic(0)
microsoft corrente disattiva il threading dinamico in modo che il set esistente di thread possa essere riutilizzato per l'area parallela seguente. omp_set_dynamic(1)
attiva il threading dinamico rimuovendo il set esistente di thread e creando un nuovo set per l'area parallela futura. Il numero di thread nel nuovo set è uguale al set precedente e si basa sul valore restituito di omp_get_num_threads
. Pertanto, per ottenere prestazioni ottimali, usare omp_set_dynamic(0)
per riutilizzare i thread esistenti.
Riferimenti incrociati
3.1.8 funzione omp_get_dynamic
La omp_get_dynamic
funzione restituisce un valore diverso da zero se la regolazione dinamica dei thread è abilitata e restituisce 0 in caso contrario. Il formato è il seguente:
#include <omp.h>
int omp_get_dynamic(void);
Se l'implementazione non implementa la regolazione dinamica del numero di thread, questa funzione restituisce sempre 0. Per altre informazioni, vedere omp_set_dynamic.
Riferimenti incrociati
- Per una descrizione della regolazione dinamica del thread, vedere omp_set_dynamic.
3.1.9 funzione omp_set_nested
La omp_set_nested
funzione abilita o disabilita il parallelismo annidato. Il formato è il seguente:
#include <omp.h>
void omp_set_nested(int nested);
Se annidato restituisce 0, il parallelismo annidato è disabilitato, ovvero l'impostazione predefinita e le aree parallele annidate vengono serializzate ed eseguite dal thread corrente. In caso contrario, il parallelismo annidato è abilitato e le aree parallele annidate possono distribuire thread aggiuntivi per formare team annidati.
Questa funzione ha gli effetti descritti in precedenza quando viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce zero. Se viene chiamato da una parte del programma in cui la omp_in_parallel
funzione restituisce un valore diverso da zero, il comportamento di questa funzione non è definito.
Questa chiamata ha la precedenza sulla variabile di OMP_NESTED
ambiente.
Quando il parallelismo annidato è abilitato, il numero di thread usati per eseguire aree parallele annidate è definito dall'implementazione. Di conseguenza, le implementazioni conformi a OpenMP possono serializzare aree parallele annidate anche quando è abilitato il parallelismo annidato.
Riferimenti incrociati
3.1.10 omp_get_nested funzione
La omp_get_nested
funzione restituisce un valore diverso da zero se il parallelismo annidato è abilitato e 0 se è disabilitato. Per altre informazioni sul parallelismo annidato, vedere omp_set_nested. Il formato è il seguente:
#include <omp.h>
int omp_get_nested(void);
Se un'implementazione non implementa il parallelismo annidato, questa funzione restituisce sempre 0.
3.2 Funzioni di blocco
Le funzioni descritte in questa sezione modificano i blocchi usati per la sincronizzazione.
Per le funzioni seguenti, la variabile lock deve avere il tipo omp_lock_t
. Questa variabile deve essere accessibile solo tramite queste funzioni. Tutte le funzioni di blocco richiedono un argomento con un puntatore al omp_lock_t
tipo.
- La funzione omp_init_lock inizializza un blocco semplice.
- La funzione omp_destroy_lock rimuove un blocco semplice.
- La funzione omp_set_lock attende fino a quando non è disponibile un blocco semplice.
- La funzione omp_unset_lock rilascia un blocco semplice.
- La funzione omp_test_lock verifica un blocco semplice.
Per le funzioni seguenti, la variabile lock deve avere il tipo omp_nest_lock_t
. Questa variabile deve essere accessibile solo tramite queste funzioni. Tutte le funzioni di blocco annidabili richiedono un argomento con un puntatore al omp_nest_lock_t
tipo.
- La funzione omp_init_nest_lock inizializza un blocco annidabile.
- La funzione omp_destroy_nest_lock rimuove un blocco annidabile.
- La funzione omp_set_nest_lock attende fino a quando non è disponibile un blocco annidabile.
- La funzione omp_unset_nest_lock rilascia un blocco annidabile.
- La funzione omp_test_nest_lock testa un blocco annidabile.
Le funzioni di blocco OpenMP accedono alla variabile di blocco in modo da leggere e aggiornare sempre il valore più recente della variabile di blocco. Pertanto, non è necessario che un programma OpenMP includa direttive esplicite flush
per assicurarsi che il valore della variabile di blocco sia coerente tra thread diversi. Potrebbe essere necessario che flush
le direttive rendano coerenti i valori di altre variabili.
3.2.1 funzioni di omp_init_lock e omp_init_nest_lock
Queste funzioni forniscono l'unico mezzo per inizializzare un blocco. Ogni funzione inizializza il blocco associato al blocco dei parametri da usare nelle chiamate future. Il formato è il seguente:
#include <omp.h>
void omp_init_lock(omp_lock_t *lock);
void omp_init_nest_lock(omp_nest_lock_t *lock);
Lo stato iniziale viene sbloccato (ovvero nessun thread è proprietario del blocco). Per un blocco annidabile, il numero di annidamento iniziale è zero. Non è conforme chiamare una di queste routine con una variabile di blocco già inizializzata.
3.2.2 funzioni di omp_destroy_lock e omp_destroy_nest_lock
Queste funzioni assicurano che il blocco della variabile di blocco puntato non sia inizializzato. Il formato è il seguente:
#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock);
void omp_destroy_nest_lock(omp_nest_lock_t *lock);
Non è conforme chiamare una di queste routine con una variabile di blocco non inizializzata o sbloccata.
3.2.3 funzioni di omp_set_lock e omp_set_nest_lock
Ognuna di queste funzioni blocca il thread che esegue la funzione fino a quando il blocco specificato non è disponibile e quindi imposta il blocco. Un blocco semplice è disponibile se è sbloccato. Un blocco annidabile è disponibile se è sbloccato o se è già di proprietà del thread che esegue la funzione. Il formato è il seguente:
#include <omp.h>
void omp_set_lock(omp_lock_t *lock);
void omp_set_nest_lock(omp_nest_lock_t *lock);
Per un blocco semplice, l'argomento della omp_set_lock
funzione deve puntare a una variabile di blocco inizializzata. La proprietà del blocco viene concessa al thread che esegue la funzione.
Per un blocco annidabile, l'argomento della omp_set_nest_lock
funzione deve puntare a una variabile di blocco inizializzata. Il numero di annidamento viene incrementato e il thread viene concesso o mantiene la proprietà del blocco.
3.2.4 funzioni di omp_unset_lock e omp_unset_nest_lock
Queste funzioni forniscono i mezzi per rilasciare la proprietà di un blocco. Il formato è il seguente:
#include <omp.h>
void omp_unset_lock(omp_lock_t *lock);
void omp_unset_nest_lock(omp_nest_lock_t *lock);
L'argomento di ognuna di queste funzioni deve puntare a una variabile di blocco inizializzata di proprietà del thread che esegue la funzione. Il comportamento non è definito se il thread non è proprietario di tale blocco.
Per un blocco semplice, la omp_unset_lock
funzione rilascia il thread che esegue la funzione dalla proprietà del blocco.
Per un blocco annidabile, la omp_unset_nest_lock
funzione decrementa il conteggio annidamento e rilascia il thread che esegue la funzione dalla proprietà del blocco se il conteggio risultante è zero.
3.2.5 funzioni di omp_test_lock e omp_test_nest_lock
Queste funzioni tentano di impostare un blocco ma non bloccano l'esecuzione del thread. Il formato è il seguente:
#include <omp.h>
int omp_test_lock(omp_lock_t *lock);
int omp_test_nest_lock(omp_nest_lock_t *lock);
L'argomento deve puntare a una variabile di blocco inizializzata. Queste funzioni tentano di impostare un blocco nello stesso modo di omp_set_lock
e omp_set_nest_lock
, ad eccezione del fatto che non bloccano l'esecuzione del thread.
Per un blocco semplice, la omp_test_lock
funzione restituisce un valore diverso da zero se il blocco è impostato correttamente; in caso contrario, restituisce zero.
Per un blocco annidabile, la omp_test_nest_lock
funzione restituisce il nuovo conteggio annidamento se il blocco è impostato correttamente; in caso contrario, restituisce zero.
3.3 Routine di intervallo
Le funzioni descritte in questa sezione supportano un timer a parete portatile:
- La funzione omp_get_wtime restituisce l'ora di tempo trascorso.
- La funzione omp_get_wtick restituisce secondi tra tick di clock successivi.
3.3.1 funzione omp_get_wtime
La omp_get_wtime
funzione restituisce un valore a virgola mobile a precisione doppia uguale all'ora di clock del muro trascorsa in secondi da un "tempo in passato". Il "tempo effettivo in passato" è arbitrario, ma è garantito che non venga modificato durante l'esecuzione del programma dell'applicazione. Il formato è il seguente:
#include <omp.h>
double omp_get_wtime(void);
È previsto che la funzione venga usata per misurare i tempi trascorsi, come illustrato nell'esempio seguente:
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);
I tempi restituiti sono "tempi per thread", ovvero non devono essere coerenti a livello globale in tutti i thread che partecipano a un'applicazione.
3.3.2 funzione omp_get_wtick
La omp_get_wtick
funzione restituisce un valore a virgola mobile a precisione doppia uguale al numero di secondi tra i tick di clock successivi. Il formato è il seguente:
#include <omp.h>
double omp_get_wtick(void);