Ho letto qualcosa sullo SyncRoot pattern come regola generale per evitare deadlock. E leggendo una domanda di alcuni anni fa (vedi questo link), penso di capire che alcuni usi di questo modello potrebbero non essere corretti. In particolare, mi sono concentrato sui seguenti frasi da this topic:Alcuni chiarimenti sul pattern SyncRoot: qual è il modo corretto di usare questo pattern?
Noterete una proprietà SyncRoot su molte delle collezioni in System.Collections. In retrospeced, ritengo che questa proprietà fosse un errore ... Non ci vergognamo di commettere lo stesso errore mentre costruiamo le versioni generiche di queste raccolte.
Infatti, per esempio, List<T>
classe non implementa SyncRoot
proprietà, o più correttamente è implementato in modo esplicito (vedi this answer), quindi è necessario eseguire il cast a ICollection
al fine di utilizzarlo. Ma il numero this comment afferma che rendere pubblico un campo privato SyncRoot
è una cattiva pratica come il blocco su this
(vedere this answer), come confermato anche in this comment.
Quindi, se ho capito bene, quando implemento una struttura dati non thread-safe, dal momento che potrebbe essere utilizzata in un contesto multithread, non dovrei (in realtà, non devo) fornire la proprietà SyncRoot
. Ma dovrei lasciare lo sviluppatore (che userà questa struttura dati) con il compito di associarlo a un oggetto SyncRoot privato come nel seguente codice di esempio.
public class A
{
private MyNonThreadSafeDataStructure list;
private readonly object list_SyncRoot = new object;
public Method1()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
public Method2()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
}
In sintesi, ho capito che le migliori pratiche per la sincronizzazione/bloccaggio dovrebbe essere la seguente:
- Tutti gli oggetti SyncRoot privati non dovrebbero essere esposti tramite una proprietà pubblica; in altre parole, una struttura dati personalizzata non dovrebbe fornire una proprietà pubblica
SyncRoot
(vedere anche this comment). - In generale, non è obbligatorio utilizzare oggetti privati per il blocco (vedere this answer).
- Se una classe ha più serie di operazioni che devono essere sincronizzate, ma non tra loro, dovrebbe avere più oggetti SyncRoot privati (vedere this comment).
È quanto scritto sopra l'uso corretto di questo modello?
La mia opinione è che se si vuole rendere internamente una classe thread-safe, si esegue il lock internamente (privatamente) e si documenta che la classe è generalmente thread-safe. Altrimenti, fai _no locking_, documenta che la classe non è thread-safe e lascia che i consumatori della tua classe implementino il proprio lock attorno a loro come necessario per il loro uso specifico. –