Ho trovato una contraddizione in MSDN per quanto riguarda i valori iniziali per l'archiviazione locale dei thread. This page dice:La memoria locale thread-thread inizializza i valori?
Quando vengono creati i fili, il sistema alloca una matrice di valori LPVOID per TLS, che vengono inizializzati a NULL.
Questo mi porta a credere che se io chiamo TlsGetValue con un indice valido da un thread che non ha mai chiamato TlsSetValue per lo stesso indice, quindi dovrei ottenere un puntatore nullo.
This page, comunque, dice:
Spetta al programmatore per assicurare ... che il thread chiama TlsSetValue prima di chiamare TlsGetValue.
Questo suggerisce che non è possibile fare affidamento sul valore restituito da TlsGetValue a meno che non si sia certi che sia stato inizializzato esplicitamente con TlsSetValue.
Tuttavia la second page simultaneamente rinforza il comportamento inizializzato a zero da anche dicendo:
I dati memorizzati in uno slot TLS possono avere un valore di 0 perché ha ancora il suo valore iniziale o perché il filo chiamato la funzione TlsSetValue con 0.
Così ho due affermazioni dicendo che i dati viene inizializzato a null (o 0), e uno dicendo che devo inizializzare in modo esplicito prima di leggere il valore. Sperimentalmente, i valori sembrano essere inizializzati automaticamente con puntatori nulli, ma non ho modo di sapere se sono solo fortunato e se sarà sempre così.
Sto cercando di evitare l'utilizzo di una DLL solo per allocare su DLL_THREAD_ATTACH. Mi piacerebbe fare allocazione pigra lungo le linee di:
LPVOID pMyData = ::TlsGetValue(g_index);
if (pMyData == nullptr) {
pMyData = /* some allocation and initialization*/;
// bail out if allocation or initialization failed
::TlsSetValue(g_index, pMyData);
}
DoSomethingWith(pMyData);
È un modello affidabile e sicuro? O devo inizializzare esplicitamente lo slot in ogni discussione prima che io provi a leggerlo?
UPDATE: La documentazione dice anche che TlsAlloc zeros out the slots for the allocated index. Quindi, se uno slot è stato utilizzato in precedenza da un'altra parte del programma, sembra irrilevante.
Bel ragionamento, ma si scopre che TlsAlloc re-inizializzerà gli slot a zero, quindi il componente B tornerà a 0 anziché il valore spazzatura lasciato dal componente A. Ho aggiunto una risposta con maggiori dettagli. –
@Adrian Reinizializza lo slot per il thread corrente. Gli altri fili sono ancora fottuti, credo. [AGGIORNAMENTO: gli altri thread non sono effettivamente avvitati. Sono azzerati al tempo TlsFree.] –
Grazie per il look in più. Ho anche giocato abbastanza per vedere che sono reinizializzati su TlsFree, ma non avevo ancora controllato gli altri thread. –