Pergunta

Eu entendo a função principal da palavra-chave de bloqueio do MSDN

instrução lock (referência C#)

A palavra-chave de bloqueio marca um bloco de declaração como uma seção crítica, obtendo o bloqueio de exclusão mútua para um determinado objeto, executando uma instrução e liberando o bloqueio.

Quando a fechadura deve ser usada?

Por exemplo, faz sentido com aplicativos multithread porque protege os dados.Mas é necessário quando o aplicativo não gera nenhum outro thread?

Existem problemas de desempenho com o uso do bloqueio?

Acabei de herdar um aplicativo que está usando lock em todos os lugares e é de thread único e quero saber se devo deixá-los ativados, eles são mesmo necessários?

Observe que esta é mais uma questão de conhecimento geral, a velocidade do aplicativo é boa, quero saber se esse é um bom padrão de design a ser seguido no futuro ou se deve ser evitado, a menos que seja absolutamente necessário.

Foi útil?

Solução

Quando a fechadura deve ser usada?

Um bloqueio deve ser usado para proteger recursos compartilhados em código multithread.Não por mais nada.

Mas é necessário quando o aplicativo não gera nenhum outro thread?

Absolutamente não.É apenas uma perda de tempo.No entanto, certifique-se de não estar usando threads do sistema implicitamente.Por exemplo, se você usar E/S assíncrona, poderá receber retornos de chamada de um thread aleatório, não do seu thread original.

Existem problemas de desempenho com o uso do bloqueio?

Sim.Eles não são muito grandes em um aplicativo de thread único, mas por que fazer chamadas desnecessárias?

...se esse for um bom padrão de design a seguir no futuro[?]

Bloquear tudo à toa é um padrão de design terrível.Se o seu código estiver cheio de bloqueios aleatórios e você decidir usar um encadeamento em segundo plano para algum trabalho, é provável que você encontre impasses.Compartilhar um recurso entre vários threads requer um design cuidadoso e quanto mais você isolar a parte complicada, melhor.

Outras dicas

Todas as respostas aqui parecem certas:A utilidade dos bloqueios é impedir que threads acessem código bloqueado simultaneamente.No entanto, existem muitas sutilezas neste campo, uma das quais é que os blocos de código bloqueados são automaticamente marcados como regiões críticas pelo Common Language Runtime.

O efeito do código ser marcado como crítico é que, se toda a região não puder ser totalmente executada, o tempo de execução poderá considerar que todo o seu domínio de aplicação está potencialmente comprometido e, portanto, descarregá-lo da memória.Citar MSDN:

Por exemplo, considere uma tarefa que tenta alocar memória enquanto mantém um bloqueio.Se a alocação de memória falhar, abortar a tarefa atual não é suficiente para garantir a estabilidade do AppDomain, pois pode haver outras tarefas no domínio aguardando o mesmo bloqueio.Se a tarefa atual for encerrada, outras tarefas poderão entrar em conflito.

Portanto, mesmo que seu aplicativo seja de thread único, isso pode ser um perigo para você.Considere que um método em um bloco bloqueado lança uma exceção que eventualmente não é tratada dentro do bloco.Mesmo que a exceção seja tratada à medida que surge na pilha de chamadas, sua região crítica do código não terminou normalmente.E quem sabe como o CLR reagirá?

Para mais informações, leia este artigo sobre os perigos de Thread.Abort().

Lembre-se de que pode haver motivos pelos quais seu aplicativo não seja tão single-thread quanto você pensa.A E/S assíncrona no .NET pode muito bem retornar a chamada em um thread de pool, por exemplo, assim como algumas das várias classes de timer (embora não o Timer do Windows Forms).

De modo geral, se seu aplicativo for de thread único, você não aproveitará muito a instrução lock.Não conhecendo exatamente sua aplicação, não sei se elas são úteis ou não - mas suspeito que não.Além disso, se seu aplicativo estiver usando lock em todos os lugares, não sei se me sentiria tão confiante sobre ele funcionar em um ambiente multithread de qualquer maneira - o desenvolvedor original na verdade sabem como desenvolver código multithread ou eles apenas adicionaram instruções de bloqueio em todos os lugares, na vaga esperança de que isso resolveria o problema?

lock deve ser usado em torno do código que modifica o estado compartilhado, estado que é modificado por outros threads simultaneamente, e esses outros passos devem ter o mesmo bloqueio.

Um bloqueio é na verdade um serializador de acesso à memória, os threads (que recebem o bloqueio) aguardarão a entrada do bloqueio até que o thread atual saia do bloqueio, então o acesso à memória é serializado.

Para responder à sua pergunta, o bloqueio não é necessário em um único aplicativo de thread e tem efeitos colaterais no desempenho.porque os bloqueios em C# são baseados em objetos de sincronização do kernel e cada bloqueio que você executa cria uma transição do modo de usuário para o modo kernel.

Se você estiver interessado em desempenho multithreading, um bom lugar para começar é Diretrizes de threading do MSDN

Você pode tem problemas de desempenho com o bloqueio de variáveis, mas normalmente você construiria seu código para minimizar o tempo gasto dentro de um bloco de código 'bloqueado'.

No que diz respeito a remover as fechaduras.Dependerá do que exatamente o código está fazendo.Mesmo sendo de thread único, se o seu objeto for implementado como Singleton, é possível que você tenha vários clientes usando uma instância dele (na memória, em um servidor) ao mesmo tempo.

Sim, haverá alguma penalidade de desempenho ao usar o bloqueio, mas geralmente é insignificante o suficiente para não importar.

O uso de bloqueios (ou qualquer outra instrução ou construção de exclusão mútua) geralmente só é necessário em cenários multithread, onde vários threads (de sua própria criação ou de seu chamador) têm a oportunidade de interagir com o objeto e alterar o estado subjacente ou dados mantidos.Por exemplo, se você possui uma coleção que pode ser acessada por vários threads, você não deseja que um thread altere o conteúdo dessa coleção removendo um item enquanto outro thread tenta lê-lo.

Lock(token) é usado apenas para marcar um ou mais blocos de código que não devem ser executados simultaneamente em vários threads.Se o seu aplicativo for de thread único, ele estará protegendo contra uma condição que não pode existir.

E o bloqueio provoca um impacto no desempenho, adicionando instruções para verificar o acesso simultâneo antes que o código seja executado.Só deve ser usado quando necessário.

Veja o pergunta sobre 'Mutex' em C#.E então olhe para esses dois perguntas sobre o uso da instrução 'lock(Object)' especificamente.

Não faz sentido ter bloqueios no aplicativo se houver apenas um thread e, sim, é um impacto no desempenho, embora seja necessário um bom número de chamadas para que esse acerto se transforme em algo significativo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top