Primeiro - a maioria das aulas nunca precisará ser segura para threads. Use YAGNI : aplique a segurança de threads apenas quando você souber que realmente vai usá-lo (e testá-lo).
Para o material no nível do método, existe [MethodImpl]:
[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}
Isso também pode ser usado em acessadores (propriedades e eventos):
private int i;
public int SomeProperty
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return i; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { i = value; }
}
Observe que os eventos do tipo campo são sincronizados por padrão, enquanto as propriedades implementadas automaticamente não são :
public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized
Pessoalmente, não gosto da implementação de MethodImplcomo ela bloqueia thisou typeof(Foo)- o que é contra as melhores práticas. A opção preferida é usar seus próprios bloqueios:
private readonly object syncLock = new object();
public void SomeMethod() {
lock(syncLock) { /* code */ }
}
Observe que, para eventos do tipo campo, a implementação de bloqueio depende do compilador; em compiladores mais antigos da Microsoft, é um lock(this)/ lock(Type)- no entanto, em compiladores mais recentes, ele usaInterlocked atualizações -, portanto, são seguros para threads sem as partes desagradáveis.
Isso permite um uso mais granular e permite o uso de Monitor.Wait /Monitor.Pulse etc para se comunicar entre os threads.
Uma entrada de blog relacionada ( revisitada posteriormente ).