Desde a primeira versão do .NET Framework, temos a keyword lock. Com ela, podemos criar um bloco de código que será acessado por uma única thread de cada vez. Na verdade, depois de compilado, esse bloco é transformado em chamadas para os métodos Enter e Exit, respectivamente, expostos pela classe Monitor (System.Threading), e envolvido por um bloco try/finally. Imagine o seguinte código:
lock (_meuLock)
{
//código “protegido”
}
Ao ser compilado, esse código será transformado em:
Monitor.Enter(_meuLock);
try
{
//código “protegido”
}
finally
{
Monitor.Exit(_meuLock);
}
O problema disso é que, segundo o Joe Duffy, exceções podem acontecer entre o método Enter (que é responsável por adquirir o lock) e o bloco try; isso dará origem ao que ele chama de “bloqueios orfãos”, já que nunca serão liberados, pois o bloco finally não será disparado.
Para resolver isso, a Microsoft criou uma nova versão (overload) do método Enter, que além do objeto que representa o lock, recebe um parâmetro boleano indicando se o lock foi ou não adquirido com sucesso. O valor retornado por esse parâmetro boleano, será avaliado mais tarde, que determinará se o método Exit correspondente deverá ou não ser invocado. Além dessa mudança, o método Enter passa a ser chamado dentro do bloco try, garantindo assim que o bloco finally seja disparado e, consequentemente, liberando o lock. O mesmo código acima, a partir da versão 4.0 do .NET Framework, passa a ser compilado da seguinte forma:
bool taken = false;
try
{
Monitor.Enter(_meuLock, ref taken);
//código protegido
}
finally
{
if (taken)
Monitor.Exit(_meuLock);
}
Obrigado por compartilhar essas mudanças que até então ainda não tinha "visto". Realmente o 4.0 está repleto de melhorias.