Questão de Programação — C — Avança SP 2025
- Código
- qg415718
- Banca
- Avança SP
- Órgão
- Prefeitura de Caconde - SP
- Ano
- 2025
- Nível
- Médio
- Cargo
- Técnico em Informática
- Alock
- Bvolatile
- Casync
- Dawait
- Eyield
GabaritoA — lock
lockGabarito: letra A. A palavra-chave lock do C# é exatamente o mecanismo que obtém o bloqueio de exclusão mútua sobre um objeto, executa o bloco de código e libera o bloqueio ao final, garantindo que apenas uma thread por vez execute aquela seção crítica. As demais alternativas (volatile, async, await, yield) têm funções completamente diferentes na linguagem, como veremos.
O conceito central aqui é o de exclusão mútua e seção crítica. Quando múltiplas threads acessam e modificam um mesmo recurso compartilhado (uma variável, uma lista, um arquivo), pode ocorrer uma condição de corrida (race condition), em que o resultado final depende da ordem imprevisível de execução das threads. Para evitar isso, é preciso garantir que apenas uma thread por vez entre na região que manipula o recurso — essa região é a seção crítica. O lock do C# é a forma mais simples e direta de implementar essa proteção: ele recebe um objeto como argumento (o lock object), tenta adquirir o bloqueio exclusivo sobre ele e, se conseguir, executa o bloco; ao sair do bloco (normalmente ou por exceção), o bloqueio é liberado automaticamente. Internamente, o lock é equivalente a usar Monitor.Enter e Monitor.Exit com um bloco try/finally, garantindo a liberação mesmo em caso de erro.
Na prática, o uso típico é:
private readonly object _lockObj = new object();
public void MetodoSeguro()
{
lock (_lockObj)
{
// seção crítica: apenas uma thread por vez executa este trecho
}
}O objeto usado no lock serve como identificador do bloqueio: todas as threads que usarem o mesmo objeto para lock competem entre si; se usarem objetos diferentes, não há exclusão mútua entre elas. Por isso, a prática recomendada é usar um objeto privado dedicado, nunca this ou um tipo público, para evitar bloqueios indevidos.
A distinção que importa nesta questão é entre lock e as outras palavras-chave: volatile é um modificador que informa ao compilador que o campo pode ser alterado por múltiplas threads e que a leitura/escrita deve ser atômica e visível imediatamente — mas não cria exclusão mútua nem impede que duas threads entrem simultaneamente em um bloco. async e await são usados para programação assíncrona, permitindo que uma operação que demora (como I/O) não bloqueie a thread, mas não têm relação com exclusão mútua. yield é usado em iteradores para produzir uma sequência de valores, também sem relação com concorrência.
A pegadinha que a banca explora aqui é justamente a confusão entre sincronização de acesso (lock) e visibilidade de memória (volatile). O candidato que sabe que volatile tem algo a ver com threads pode marcá-lo, mas ele não garante que apenas uma thread execute um bloco — ele apenas garante que o valor da variável seja lido da memória principal, não de um cache local. A exclusão mútua é o papel do lock.
Guarde a fronteira: lock = exclusão mútua (uma thread por vez); volatile = visibilidade (leitura/escrita atômica, sem cache). É exatamente nessa fronteira que as alternativas se dividem.
A palavra-chave lock é a resposta. Ela implementa exatamente o comportamento descrito no enunciado: obtém o bloqueio de exclusão mútua sobre um objeto, executa o bloco de instruções e libera o bloqueio ao final. É o mecanismo padrão do C# para proteger seções críticas contra acesso concorrente.
volatile é um modificador de campo que garante que leituras e escritas sejam feitas diretamente na memória principal, sem cache local da thread. Ele não impede que duas threads executem o mesmo bloco simultaneamente — não há exclusão mútua. A confusão é comum porque volatile também é usado em cenários multithread, mas com finalidade distinta: visibilidade, não exclusão.
async é um modificador que marca um método como assíncrono, permitindo que ele use await para liberar a thread durante operações de longa duração. Não tem qualquer relação com exclusão mútua ou bloqueio de threads.
await é usado dentro de métodos async para aguardar a conclusão de uma operação assíncrona sem bloquear a thread. Também não tem relação com exclusão mútua.
yield é usado em iteradores para retornar uma sequência de valores sob demanda (lazy evaluation). Não tem relação com concorrência ou exclusão mútua.
A banca explora a confusão entre lock e volatile. Ambos aparecem em contextos de multithreading, mas volatile apenas garante visibilidade de memória — não impede que duas threads entrem no mesmo bloco. Se a alternativa pede "apenas uma thread por vez", a resposta é sempre lock (ou Monitor), nunca volatile.
Para fixar, lembre-se: lock = portaria com segurança (um de cada vez); volatile = outdoor atualizado (todo mundo vê o valor novo). Quando a questão falar em "exclusão mútua", "seção crítica", "uma thread por vez", marque lock sem hesitar.
Gabarito: letra A
Link permanente: /questoes/qg415718