2014-07-09 13 views
9

Voglio creare un thread C++ 11 che voglio che venga eseguito sul mio primo core. Trovo che pthread_setaffinity_np e sched_setaffinity possono modificare l'affinità della CPU di un thread e migrarlo alla CPU specificata. Tuttavia questa specifica di affinità cambia dopo che il thread è stato eseguito.Impostare affinità CPU quando si crea un thread

Come è possibile creare un thread C++ 11 con affinità CPU specifica (un oggetto cpu_set_t)?

Se non è possibile specificare l'affinità quando si inizializza un filo C++ 11, come posso farlo con pthread_t in C?

Il mio ambiente è G ++ su Ubuntu. Un pezzo di codice è apprezzato.

+0

dispiace dire che non credo che C++ 11 supporta questo (presumibilmente a causa di problemi di portabilità) - potrebbe essere necessario scavare 'std :: thread' e iniziare il filo con' pthread_create' e un attributo che hai preparati con [ 'pthread_attr_setaffinity_np'] (http://man7.org/linux/man-pages/man3/pthread_attr_setaffinity_np.3.html), oppure utilizzare' std :: thread' e hanno il thread creato impostato immediatamente la propria affinità (evitando le condizioni di gara che avresti se provassi ad impostarlo dal thread di creazione). –

+0

@ Tony Grazie mille. Ho aggiunto il codice nella risposta. Spero che sia quello che hai suggerito. –

+0

sembra giusto ... applausi. –

risposta

-6

Dopo aver cercato per un po ', sembra che non possiamo impostare l'affinità della CPU quando creiamo un C++ thread.

La ragione è che, c'è PRIVA secondo l'affinità quando creare un thread. Quindi, perché preoccuparsi di renderlo possibile nella lingua.

Dire, vogliamo che il carico di lavoro f() sia associato alla CPU0. Possiamo semplicemente modificare l'affinità con CPU0 subito prima del il vero carico di lavoro chiamando lo pthread_setaffinity_np.

Tuttavia, abbiamo CAN specificare l'affinità quando si crea un thread in C. (grazie al commento di Tony D). Ad esempio, il codice seguente mostra "Hello pthread".

void *f(void *p) { 
    std::cout<<"Hello pthread"<<std::endl; 
} 

cpu_set_t cpuset; 
CPU_ZERO(&cpuset); 
CPU_SET(0, &cpuset); 
pthread_attr_t pta; 
pthread_attr_init(&pta); 
pthread_attr_setaffinity_np(&pta, sizeof(cpuset), &cpuset); 
pthread_t thread; 
if (pthread_create(&thread, &pta, f, NULL) != 0) { 
    std::cerr << "Error in creating thread" << std::endl; 
} 
pthread_join(thread, NULL); 
pthread_attr_destroy(&pta); 
+1

Risposta errata. Stai usando i grassetti per fare affermazioni troppo ampie sui casi d'uso. pthread_setaffinity_np cambia il thread del processo attualmente in esecuzione, causando un interruttore di contesto non necessario. – ACyclic

+0

@ACyclic, cosa intendi con "cambia il thread del processo attualmente in esecuzione"? Inoltre, nota, dalla pagina man: La funzione pthread_setaffinity_np() imposta la maschera di affinità CPU di il thread thread per il set CPU indicato da cpuset – aho

+0

"Il motivo è che, non c'è bisogno di specificare l'affinità quando si crea una discussione, quindi, perché preoccuparsi di renderlo possibile nella lingua. "... così divertente. – Alex

15

Mi dispiace di essere il "mito Buster" qui, ma l'impostazione affinità di thread ha una grande importanza, e cresce in importanza nel corso del tempo, come i sistemi di tutti usiamo diventiamo sempre più NUMA (Non-Uniform Memory Architettura) per natura. Anche un semplice server dual socket in questi giorni ha una RAM collegata separatamente a ciascun socket e la differenza di accesso alla memoria da un socket alla propria RAM a quella del socket del processore adiacente (RAM remota) è notevole. Nel prossimo futuro, i processori stanno raggiungendo il mercato in cui il set interno di core è NUMA in sé (controller di memoria separati per gruppi separati di core, ecc.). Non ho bisogno di ripetere qui il lavoro degli altri, basta cercare "NUMA e thread affinity" online - e puoi imparare da anni di esperienza di altri ingegneri.

Non impostare l'affinità del thread è effettivamente uguale a "sperare" che lo scheduler del SO gestisca correttamente l'affinità del thread. Lasciatemi spiegare: Hai un sistema con alcuni nodi NUMA (domini di elaborazione e memoria). Si avvia una discussione e il thread esegue alcune operazioni con la memoria, ad es. malloc un po 'di memoria e poi processo ecc. Il sistema operativo moderno (almeno Linux, probabilmente anche altri) fa un buon lavoro fino ad ora, la memoria è, per impostazione predefinita, allocata (se disponibile) dallo stesso dominio della CPU su cui è in esecuzione il thread . Al momento, il sistema di condivisione del tempo (tutto il sistema operativo moderno) farà passare il thread. Quando il thread viene reinserito nello stato di esecuzione, può essere reso eseguibile su qualsiasi dei nuclei nel sistema (poiché non è stata impostata una maschera di affinità) e più grande è il sistema, maggiori sono le possibilità che sarà "riattivato" su una CPU che è remota rispetto alla memoria precedentemente allocata o utilizzata. Ora, tutti gli accessi alla memoria sarebbero remoti (non sono sicuro cosa significhi per le prestazioni dell'applicazione?maggiori informazioni sull'accesso remoto alla memoria sui sistemi NUMA online)

Quindi, per riassumere, le interfacce di impostazione dell'affinità sono MOLTO importanti quando si esegue il codice su sistemi che hanno un'architettura più che banale - che sta rapidamente diventando "qualsiasi sistema" questi giorni. Alcuni filo runtime ambienti/librerie consentono il controllo di questo in fase di esecuzione, senza alcuna programmazione specifica (vedi OpenMP, per esempio nella realizzazione di Intel di variabile d'ambiente KMP_AFFINITY) - e sarebbe la cosa giusta per il C++ 11 esecutori ad includere meccanismi simili a le loro librerie libere e le opzioni di linguaggio (e fino a quel momento, se il tuo codice è destinato ai server, ti consiglio vivamente di implementare il controllo di affinità nel tuo codice)

+0

+1 Windows è un buon esempio di come "sperare che il sistema operativo funzioni correttamente" può andare storto. Almeno sotto Win7 (non ho provato 8 o 10) i thread hanno finito per assegnare un round-robin core preferito. Il che è molto semplice e giusto il 95% delle volte. Ma il restante 5% è davvero, davvero amaro. – Damon

+0

Questo si applica solo ai processi con carichi di lavoro facilmente prevedibili. Dovrai essere molto più intelligente per battere gli scheduler del futuro prossimo e i loro ottimizzatori, che hanno sempre maggiori probabilità di ottenere prestazioni dai recenti progressi nell'IA. – Domi

1

In C++ 11 non puoi impostare l'affinità del thread quando il thread è creato (a meno che la funzione che viene eseguito nel thread lo fa da solo), ma una volta che si crea il filo, è possibile impostare l'affinità tramite qualunque interfaccia nativa avete ottenendo la maniglia nativo per il filo (thread.native_handle ()), quindi per Linux è possibile ottenere il prefisso tramite:

pthread_t my_thread_native = my_thread.native_handle();

Quindi è possibile utilizzare una qualsiasi delle chiamate pthread che passano in my_thread_native dove vuole solo l'ID pthread.

Si noti che la maggior parte delle funzionalità di thread sono specifiche dell'implementazione, vale a dire pthreads, thread di Windows, thread nativi per altri sistemi operativi hanno tutti la propria interfaccia e tipi questa parte del codice non sarebbe molto portabile.

Problemi correlati