Premièrement - la plupart des classes n'auront jamais besoin d'être thread-safe. Utilisez YAGNI : n'appliquez la sécurité des threads que lorsque vous savez que vous allez réellement l'utiliser (et le tester).
Pour les choses au niveau de la méthode, il y a [MethodImpl]
:
[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}
Cela peut également être utilisé sur les accesseurs (propriétés et événements):
private int i;
public int SomeProperty
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return i; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { i = value; }
}
Notez que les événements de type champ sont synchronisés par défaut, tandis que les propriétés implémentées automatiquement ne le sont pas :
public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized
Personnellement, je n'aime pas l'implémentation MethodImpl
car elle se verrouille this
ou typeof(Foo)
- ce qui est contraire aux meilleures pratiques. L'option préférée consiste à utiliser vos propres verrous:
private readonly object syncLock = new object();
public void SomeMethod() {
lock(syncLock) { /* code */ }
}
Notez que pour les événements de type champ, l'implémentation de verrouillage dépend du compilateur; dans les anciens compilateurs Microsoft, il s'agit d'un lock(this)
/ lock(Type)
- cependant, dans les compilateurs plus récents, il utilise desInterlocked
mises à jour - donc thread-safe sans les parties désagréables.
Cela permet une utilisation plus granulaire et permet l'utilisation de Monitor.Wait
/ Monitor.Pulse
etc pour communiquer entre les threads.
Une entrée de blog connexe ( revisitée plus tard ).