Implementando Observer em C# com Dependency Injection
Guia Completo de Lock & Monitor para Sincronização Threads
Imagine que você tenha várias threads ou processos tentando acessar e modificar a mesma variável🧠 Variáveis em C#: Onde os Dados Ganham Vida (e Nome!)Descubra como as variáveis em C# funcionam, com exemplos do mundo real, boas práticas de nomeação e dicas para otimizar seu código. ao mesmo tempo - pode virar um caos! Em C#, lock
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. e
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Monitor são recursos
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. poderosos para impedir que diferentes partes do código colidam quando utilizam dados compartilhados. Eles nos ajudam a garantir que, a cada vez, apenas um pedaço de código acesse determinada área de memória, evitando resultados imprevisíveis ou comportamentos estranhos.
Neste artigo, vamos explorar como essas duas ferramentas funcionam, quando usar uma ou outra e como aplicá-las para deixar o código confiável e seguro, mesmo em cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. de concorrência avançada.
Tabela de Conteúdo🔗
- Lock: A Maneira Simples de Proteger Recursos
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos.
- Monitor: Mais Controle, Mais Poder
- Exemplo Prático
📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!Aprenda a usar Serilog em .NET para registrar logs estruturados, identificar erros e enriquecer informações, transformando seu código num enigma solucionável.: Controle de Inventário
- Dicas
🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados. para Evitar Problemas
- Considerações Finais
- O Problema
🤝 GitHub Básico: Versionamento para Iniciantes!Descubra como o GitHub facilita colaboração, versionamento e organização de código com este tutorial prático e essencial para desenvolvedores iniciantes. das Colisões
- Lock vs Monitor: Quando
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Usar Cada Um
- Deadlocks
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.: O Abismo a Ser Evitado
- Exemplo Prático
📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!Aprenda a usar Serilog em .NET para registrar logs estruturados, identificar erros e enriquecer informações, transformando seu código num enigma solucionável.: Sistema de Transações Bancárias
- Desafio Prático: Gerenciador de Estoque Multithread
Lock: A Maneira Simples de Proteger Recursos🔗
O lock🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. é um mecanismo de sincronização que faz com que apenas uma thread por vez possa executar
🔍 Comandos: Desacople Ações dos Botões!Aprenda a implementar comandos em C# para desacoplar lógica e interface usando MVVM, com exemplos práticos e dicas para melhor testabilidade e manutenção. o trecho de código dentro do seu bloco. A sintaxe é extremamente simples:
private readonly object _cadeado = new object();
public void IncrementarContador()
{
lock (_cadeado)
{
// Parte do código que só uma thread acessa por vez
contador++;
}
}
Acima, _cadeado
é um objeto usado como “chave” para sincronizar o acesso. Quando📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. uma thread entra no bloco lock
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance., ela "tranca" o objeto
_cadeado
. Qualquer outra thread que tentar executar🔍 Comandos: Desacople Ações dos Botões!Aprenda a implementar comandos em C# para desacoplar lógica e interface usando MVVM, com exemplos práticos e dicas para melhor testabilidade e manutenção. o mesmo trecho ficará em espera até a primeira thread sair do bloco.
Vantagens do Lock
- Facilidade de uso: a sintaxe é curta e
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. clara.
- Evita escrever código de controle complexo: não precisamos de
try/finally
manual para liberar o bloqueio🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance..
Quando Usar
- Em cenários
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. simples, quando queremos proteger um pequeno trecho de código que manipula dados compartilhados.
- Para garantia rápida de que apenas um método acesse determinado recurso
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. (por exemplo, uma lista em memória).
Monitor: Mais Controle, Mais Poder🔗
O Monitor é outro recurso📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. disponibilizado pelo .NET que, em essência, faz algo parecido com o lock
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance., mas oferece maior controle sobre o ciclo de vida
🧠 Variáveis em C#: Onde os Dados Ganham Vida (e Nome!)Descubra como as variáveis em C# funcionam, com exemplos do mundo real, boas práticas de nomeação e dicas para otimizar seu código. do bloqueio. É muito comum vermos a seguinte forma:
private readonly object _cadeado = new object();
public void IncrementarContadorMonitor()
{
bool bloqueado = false;
try
{
Monitor.Enter(_cadeado, ref bloqueado);
// Se bloqueado for true, significa que a thread conseguiu o bloqueio
contador++;
}
finally
{
if (bloqueado)
Monitor.Exit(_cadeado);
}
}
No exemplo acima, podemos gerenciar melhor o que fazemos antes de tentar entrar no bloqueio🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance., e principalmente no
finally
, temos como garantir que o bloqueio será liberado corretamente, mesmo em cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. onde alguma exceção aconteça no meio do caminho.
Vantagens do Monitor
- Controle total: você pode saber, por exemplo, se conquistou ou não o bloqueio
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. por meio do parâmetro
bloqueado
. - Métodos
🧠 Métodos em C#: Como Criar Funções que Não São Só Enfeites!Otimize seu código em C# com métodos inteligentes. Aprenda práticas de reutilização, sobrecarga e escopo para melhorar a clareza e a eficiência. adicionais: como
Monitor.Wait()
e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades.
Monitor.Pulse()
, que permitem estratégias avançadas de sincronização.
Quando Usar
- Em cenários
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. em que é preciso mais finesse na sincronização, como quando precisamos coordenar várias threads que dependem de eventos - por exemplo, se uma thread aguarda outra completar um passo antes de continuar.
Exemplo Prático: Controle de Inventário🔗
Imagine que você tenha um sistema de vendas em que múltiplas threads estão processando pedidos simultaneamente. Qualquer thread que processar um pedido precisa checar a quantidade🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. de produto disponível antes de abater do estoque. Se duas threads fizerem isso ao mesmo tempo, podem ocorrer problemas (como deixar o estoque negativo ou liberar vendas além do limite).
Código Simplificado
public class Inventario
{
private int _quantidade;
private readonly object _cadeado = new object();
public Inventario(int quantidadeInicial)
{
_quantidade = quantidadeInicial;
}
public bool ProcessarVenda(int quantidadeVendida)
{
lock (_cadeado)
{
// Checa se há estoque
if (_quantidade >= quantidadeVendida)
{
_quantidade -= quantidadeVendida;
Console.WriteLine($"Venda concluída. Estoque restante: {_quantidade}");
return true;
}
else
{
Console.WriteLine("Estoque insuficiente para a venda.");
return false;
}
}
}
}
No código acima:
1. O trecho lock
garante que apenas uma thread por vez verifique e🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. (_cadeado)
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. modifique o
_quantidade
.
2. Se quisermos mais controle - por exemplo, esperar que o estoque seja reabastecido - usaríamos Monitor.Wait()
e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades.
Monitor.Pulse()
para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! coordenar as threads.
Dicas para Evitar Problemas🔗
1. Mantenha o Escopo do Bloqueio🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. Curto
Não deixe grandes blocos de código dentro de lock
ou 🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.
Monitor
. Quanto maior o bloco, mais tempo outra thread precisa esperar.
Em Monitor
, use try/finally
para garantir liberação mesmo em caso de exceção💥 Try/Catch: Domine Exceções antes que Elas Dominem Você!Descubra como tratar exceções em C# com práticas eficientes utilizando try/catch. Aprenda a gerenciar erros e aumentar a robustez do seu código..
3. Evite “Lock🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.” em Objetos de Terceiros
Sempre use um objeto interno, como _cadeado = new object()
, para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! não correr o risco de outra parte do sistema, sem querer, usar o mesmo objeto.
- Locks
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. aninhados (bloqueando mais de um recurso
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. ao mesmo tempo) podem gerar situações complicadas, inclusive deadlocks
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.. Planeje bem a ordem de aquisição dos recursos
📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos..
O Problema das Colisões🔗
Quando múltiplas threads acessam um recurso📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. compartilhado sem controle, ocorrem condições de corrida. Exemplo clássico:
int saldo = 1000;
void Sacar(int valor) {
if (saldo >= valor) {
saldo -= valor;
}
}
Se duas threads executarem Sacar(1000)
simultaneamente, ambas podem ver saldo >= valor
, resultando em saldo negativo! 😱🗂️ Dicionários: Acesse Dados por Chaves como um Mestre dos HashMaps!Aprenda a usar dicionários em C# de modo prático e eficiente. Nosso tutorial mostra criação, acesso e otimização para manipular dados com segurança.
Lock vs Monitor: Quando Usar Cada Um🔗
Característica | lock | Monitor |
---|---|---|
Sintaxe | Simplificada | Mais verbosa |
Controle de Espera | Não | Sim (Wait/Pulse) |
Timeout | Não | Sim (TryEnter) |
Nível de Controle | Básico | Avançado |
Casos de Uso Típicos | Sincronização simples | Filas, pools, coordenação |
Deadlocks: O Abismo a Ser Evitado🔗
O pesadelo de todo dev multithread:
// Thread 1
lock (recursoA) {
lock (recursoB) { /* ... */ }
}
// Thread 2
lock (recursoB) {
lock (recursoA) { /* ... */ }
}
Prevenção:
1. Sempre bloqueie recursos📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. na mesma ordem
2. Use Monitor.TryEnter()
com timeout
3. Considere usar SemaphoreSlim
ou Mutex
Exemplo Prático: Sistema de Transações Bancárias🔗
Implementação segura🛡️ Segurança em SignalR: Autenticação e Autorização!Descubra como implementar JWT e autorização com roles e claims no SignalR, garantindo segurança e controle de acessos em tempo real. para transferências:
public class ContaBancaria {
private decimal _saldo;
private readonly object _lock = new object();
public void Transferir(ContaBancaria destino, decimal valor) {
lock (_lock) {
lock (destino._lock) {
if (_saldo >= valor) {
_saldo -= valor;
destino._saldo += valor;
}
}
}
}
}
Dica Profissional:
Use Interlocked.CompareExchange()
para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! operações atômicas simples!
Desafio Prático: Gerenciador de Estoque Multithread🔗
Objetivo: Criar📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. um sistema que:
1. Permite atualizações concorrentes de estoque
2. Bloqueia itens durante reposição
3. Notifica quando📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. estoque está baixo
Requisitos:
- Use
lock
para🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.
🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! operações básicas
- Implemente
Monitor.Wait/Pulse
para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! notificações
- Prevenda deadlocks
🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. na reposição
Dica: Comece com esta estrutura:
public class GerenciadorEstoque {
private Dictionary<int, int> _estoque = new Dictionary<int, int>();
private readonly object _lock = new object();
public void ReporItem(int itemId, int quantidade) {
// Implemente com Monitor!
}
}
Considerações Finais🔗
Em aplicações modernas, especialmente naquelas que precisam lidar com muitas requisições simultâneas ou cálculos paralelos, é fundamental entender como proteger seções críticas do código. Lock🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance. e
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Monitor são caminhos rápidos e eficientes para garantir acesso exclusivo a dados compartilhados - basta saber usá-los com responsabilidade e boas práticas
🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados..
Essas ferramentas nos dão plena confiança de que, mesmo se várias threads tentarem acessar o mesmo “pote de ouro” ao mesmo tempo, tudo estará em ordem sem perdas ou inconsistências.
Dominar lock
e🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.
📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades.
Monitor
é essencial para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! construir sistemas multithread robustos. Lembre-se:
- Use
lock
para🚫 Deadlocks: O que São e Como Fugir Deles!Descubra o que são deadlocks em C#, aprenda com exemplos práticos e estratégias para evitar bloqueios que travam suas aplicações e comprometer performance.
🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! sincronização básica
- Recorra ao
Monitor
para cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. complexos
- Sempre teste condições de corrida
- Deadlocks são evitáveis com boas práticas
🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados.
Que tal implementar o desafio do gerenciador de estoque e compartilhar no GitHub🤝 GitHub Básico: Versionamento para Iniciantes!Descubra como o GitHub facilita colaboração, versionamento e organização de código com este tutorial prático e essencial para desenvolvedores iniciantes.? 🚀
Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.
Referências🔗
- .NET Documentation: learn.microsoft.com/pt-br/dotnet/
- Awesome .NET: github.com/quozd/awesome-dotnet
- C# Language Specification: learn.microsoft.com/pt-br/dotnet/csharp/language-reference/language-specification/
- GitHub: Microsoft/.NET: github.com/dotnet
- Microsoft Learn: C# e .NET: learn.microsoft.com/pt-br/dotnet/csharp/