2015-09-21 13 views
11

Sto avendo una funzione che deve essere eseguita n=1000 volte. Questa funzione esegue una simulazione in stile Monte Carlo e restituisce come risultato un int. Mi piacerebbe eseguire nthreads=4 in parallelo. Ogni volta che un thread termina un ciclo, dovrebbe inserire il risultato in un std::vector<int>. Quindi, dopo 1000 cicli, ho un vettore di 1000 int s che può essere esaminato dalle statistiche.Posso creare uno std :: atomic <vector<int> thread-safe>?

Poiché un std::vector non è thread-safe, ho pensato a std::mutex (che sicuramente funzionerebbe).

Ma mi chiedo se posso dichiarare un vettore come atomico e quindi aggirare i mutex? E 'possibile avere un std::atomic<std::vector<int>>? E posso usare push_back ecc. Su di esso?

+0

Did std :: atomic > compilato? – DawidPi

+0

Non riesco a provare su questa macchina ... ma mi sono imbattuto in atomico. – dani

+0

Volevo solo aggiungere che se sai fin dall'inizio che avrai 1000 esecuzioni e il tuo contenitore memorizzerà esattamente 1000 risultati, allora perché vuoi utilizzare il contenitore dinamico? So che std :: vector utilizza l'array nella sua implementazione e non sarà necessaria alcuna riallocazione se si prenota abbastanza spazio all'inizio (quindi non ci sarà alcun guadagno di prestazioni dall'uso di std :: array). – dptd

risposta

8

Non è necessario. E 'del tutto va bene, per accedere ja std::vector da più thread, se

  • avete letto gli oggetti
  • si scrive a diversi oggetti

Quindi basta assicurarsi, si crea un vettore di dimensione n=1000 e in base al numero di thread (da 1 a 4) si assegnano gli elementi 0-249, 250-499 ecc. Ai thread.

Quindi ognuno dei tuoi thread calcola gli elementi n/nthreads.

+9

È molto importante che il vettore venga ridimensionato in modo appropriato prima di assegnarne le parti ai thread: qualsiasi ridimensionamento non sarà sicuramente sicuro. – Jeremy

+1

Ma è ancora necessario sincronizzarsi tra il lettore e lo scrittore anche se lo si fa in questo modo. In particolare, ma non solo, perché non è garantito che gli accessi a 'int' siano atomici su tutte le architetture a meno che non si usi' atomic_int' o 'std :: atomic '. – blubberdiblub

4

Atomico può essere istanziato con tipi banalmente copiabili. Il vettore non è un tipo così.

+0

Una domanda non è una risposta. Si prega di scrivere domande all'OP come commento alla domanda – Gombat

+0

Un array in stile C come 'int k [1000]' a "tipo" banalmente copiabile "? – dani

+0

'k' è solo un puntatore. I puntatori sono banalmente copiabili. Ma non so se usare questo come un tavolo sarà sicuro dal fatto che 'k' è un puntatore normale, ma' k [5] 'può essere scritto come' * (k + 5) 'e' k + 5' è un puntatore diverso, ma non ne sono sicuro. Puoi controllare 'is_trivially_copyable' da' std'. Normalmente si scriverebbe il proprio tipo 'threadsafe_vector' per i contenitori thread-safe. – DawidPi

13

C++ 11 §29.5/1 dice

C'è un modello di classe generica atomica. Il tipo dell'argomento modello T deve essere banalmente copiabile (3.9).

Cosa significa banalmente copiabile?

§3.9 dice

tipi scalari, tipi di classe banalmente copiabili (Clausola 9), array di tali tipi e le versioni cv qualificati di questi tipi (3.9.3) vengono chiamati collettivamente banalmente tipi copiabili.

Per i tipi di classe (di cui std::vector è):

Un banalmente classe copiabile è una classe che:

  • non ci sono costruttori di copia non banali
  • non ha non -trivial move constructors
  • non ha operatori di assegnazione copie non banali
  • non ha operatori di assegnazione mossa non banali
  • ha un distruttore banale

In base a questa lista std::vector non è banalmente copiabile e quindi non è possibile utilizzare std::atomic<std::vector<int>>.

Dal momento che si conosce la dimensione in anticipo e dal momento che non c'è bisogno di utilizzare metodi che richiederebbero il vettore essere riallocati in una posizione diversa (come push_back). È possibile utilizzare std::vector<int>::resize o il costruttore dimensioni per preallocare e preconstruct la richiesta int s. Pertanto i thread simultanei non hanno bisogno di operare sul vettore stesso, ma sugli elementi.

Se non c'è l'accesso da diversi thread allo stesso elemento non c'è condizione di competizione.

lo stesso vale per int k[1000] che è banalmente copiabile, ma non è necessario che sia in i thread non cambiano la matrice/vettore/elenco stesso ma gli elementi.

Problemi correlati