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 MethodImpl
como ela bloqueia this
ou 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 ).