Domanda

Ho oggetti di funzione piccoli ma usati frequentemente.Ogni thread ottiene la propria copia.Tutto è assegnato staticamente.Le copie non condividono dati globali o statici.Devo proteggere questi oggetti da false condivisione?

Grazie. Modifica: Ecco un programma giocattolo che utilizza Boost.Threads.La condivisione falsa può verificarsi per il campo Data ?

#include <boost/thread/thread.hpp>

struct Work {
    void operator()() {
        ++data;
    }

    int data;
};

int main() {
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work());
    threads.join_all();
}
.

È stato utile?

Soluzione

False condivisione tra i fili è quando 2 o più filettature utilizzano la stessa linea di cache.

E.G. :

struct Work {
    Work( int& d) : data( d ) {}
    void operator()() {
        ++data;
    }

    int& data;
};

int main() {
    int false_sharing[10] = { 0 };
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(false_sharing[i]));
    threads.join_all();

    int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 };
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS]));
    threads.join_all();
}
.

I fili nel primo blocco soffrono di condivisione falsa. I fili nel secondo blocco non sono (grazie a CACHELINE_SIZE).

I dati sulla pila sono sempre lontani "lontano da altri thread. (Ad es. Sotto Windows, almeno un paio di pagine).

Con la tua definizione di un oggetto funzione, può essere visualizzata la condivisione falsa, poiché le istanze di Work vengono create sul mucchio e questo spazio heap viene utilizzato all'interno del filo.

Questo può portare a diverse istanze Work da adiacenti e quindi potrebbe incorrere in condivisione di linee di cache.

Ma ... il tuo campione non ha senso, perché i dati non vengono mai toccati all'esterno e quindi la condivisione falsa viene indotta inutilmente.

Il modo più semplice, per evitare problemi come questo, è quello di copiare i dati "condivisi" localmente sullo stack, quindi lavorare sulla copia dello stack. Quando il tuo lavoro è finito di copiarlo sul var di output.

E.G:

struct Work {
    Work( int& d) : data( d ) {}
    void operator()()
    {
        int tmp = data;
        for( int i = 0; i < lengthy_op; ++i )
           ++tmp;
        data = tmp;
    }

    int& data;
};
.

Questo impedisce tutti i problemi con la condivisione.

Altri suggerimenti

Ho fatto un bel po 'di ricerca e sembra che non vi sia alcuna soluzione di proiettile d'argento alla condivisione falsa.Ecco cosa vengo con (grazie a Christopher): 1) Pad dei dati da entrambi i lati con roba non utilizzata o meno frequentemente utilizzata. 2) Copia i tuoi dati in Stack e copialo indietro dopo che tutto il duro lavoro è finito. 3) Utilizzare l'allocazione della memoria allineata alla cache.

I 'Non ti sento completamente sicuro con i dettagli, ma qui è il mio take:

(1) Il tuo esempio semplificato è rotto poiché aumentare create_thread prevede un riferimento, si passa un temporaneo.

(2) Se si utilizza vector<Work> con un elemento FRO a ciascun thread o OTThWise li ha in memoria sequenzialmente, si verificherà la condivisione falsa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top