evento
Crie aplicativos e agentes de IA
17/03, 21 - 21/03, 10
Junte-se à série meetup para criar soluções de IA escaláveis com base em casos de uso do mundo real com outros desenvolvedores e especialistas.
Registe-se agoraEste browser já não é suportado.
Atualize para o Microsoft Edge para tirar partido das mais recentes funcionalidades, atualizações de segurança e de suporte técnico.
Lock
objetoNota
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Questão campeã: https://github.com/dotnet/csharplang/issues/7104
Especificar como System.Threading.Lock
interage com a palavra-chave lock
(chamando o seu método EnterScope
em segundo plano).
Adicione avisos de análise estática para evitar o uso indevido acidental do tipo, sempre que possível.
O .NET 9 está introduzindo um novo tipo System.Threading.Lock
como uma alternativa melhor ao bloqueio baseado em monitor existente.
A presença da palavra-chave lock
em C# pode levar os desenvolvedores a pensar que podem usá-la com esse novo tipo.
Fazer isso não bloquearia segundo a semântica desse tipo, mas sim tratá-lo-ia como qualquer outro objeto e usaria o bloqueio baseado em monitor.
namespace System.Threading
{
public sealed class Lock
{
public void Enter();
public void Exit();
public Scope EnterScope();
public ref struct Scope
{
public void Dispose();
}
}
}
A semântica da instrução de bloqueio (§13.13) é alterada para tratar especificamente o tipo System.Threading.Lock
.
Uma declaração
lock
do formuláriolock (x) { ... }
- em que
x
é uma expressão do tipoSystem.Threading.Lock
, é precisamente equivalente a:eusing (x.EnterScope()) { ... }
System.Threading.Lock
devem ter a seguinte forma:namespace System.Threading { public sealed class Lock { public Scope EnterScope(); public ref struct Scope { public void Dispose(); } } }
- onde
x
é uma expressão de um reference_type, é precisamente equivalente a: [...]
Observe que a forma pode não estar totalmente verificada (por exemplo, não haverá erros nem avisos se o tipo Lock
não for sealed
), mas o recurso pode não funcionar como esperado (por exemplo, não haverá avisos ao converter Lock
em um tipo derivado, já que o recurso assume que não há tipos derivados).
Além disso, novos avisos são adicionados às conversões de referência implícitas (§10.2.8) ao atualizar o tipo de System.Threading.Lock
:
As conversões de referência implícitas são:
- De qualquer tipo de referência a
object
edynamic
.
- Um aviso é gerado quando é sabido que o reference_type está
System.Threading.Lock
.- De qualquer class_type
S
a qualquer class_typeT
, desde queS
derive deT
.
- Um aviso é emitido quando se sabe que
S
System.Threading.Lock
.- De qualquer class_type
S
para qualquer interface_typeT
, desde queS
implementeT
.
- Um aviso é comunicado quando se sabe que
S
estáSystem.Threading.Lock
.- [...]
object l = new System.Threading.Lock(); // warning
lock (l) { } // monitor-based locking is used here
Observe que esse aviso ocorre mesmo para conversões explícitas equivalentes.
O compilador evita relatar o aviso em alguns casos quando a instância não pode ser bloqueada após a conversão para object
:
var l = new System.Threading.Lock();
if (l != null) // no warning even though `l` is implicitly converted to `object` for `operator!=(object, object)`
// ...
Para escapar do aviso e forçar o uso do bloqueio baseado em monitor, pode-se usar
#pragma warning disable
),Monitor
APIs diretamente,object AsObject<T>(T l) => (object)l;
.Suporte a um padrão geral que outros tipos também podem usar para interagir com a palavra-chave lock
.
Este é um trabalho futuro que poderá ser implementado quando ref struct
puder participar em genéricos.
Discutido em LDM 2023-12-04.
Para evitar ambiguidade entre o bloqueio baseado em monitor existente e o novo Lock
(ou padrão no futuro), poderíamos:
lock
existente.struct
s (uma vez que o lock
existente não permite tipos de valor).
Pode haver problemas com construtores padrão e operações de cópia se as structs tiverem inicialização lenta.O codegen pode ser fortalecido contra interrupções de threads (que estão obsoletos).
Poderíamos avisar também quando Lock
é passado como um parâmetro de tipo, porque o bloqueamento em um parâmetro de tipo sempre usa bloqueamento baseado em monitor:
M(new Lock()); // could warn here
void M<T>(T x) // (specifying `where T : Lock` makes no difference)
{
lock (x) { } // because this uses Monitor
}
No entanto, isso causaria avisos ao armazenar Lock
s em uma lista que é indesejável:
List<Lock> list = new();
list.Add(new Lock()); // would warn here
Poderíamos incluir a análise estática para evitar o uso de System.Threading.Lock
em using
s com await
s.
Ou seja, podemos emitir um erro ou um aviso para um código como using (lockVar.EnterScope()) { await ... }
.
Atualmente, isso não é necessário, uma vez que Lock.Scope
é um ref struct
, de modo que o código é ilegal de qualquer maneira.
No entanto, se alguma vez permitíssemos ref struct
s em métodos async
ou mudássemos Lock.Scope
para não ser um ref struct
, esta análise tornar-se-ia benéfica.
(Também provavelmente precisaríamos considerar para isso todos os tipos de bloqueio correspondentes ao padrão geral, se implementados no futuro. Embora possa ser necessário um mecanismo de exclusão, pois alguns tipos de bloqueio podem ser permitidos para serem usados com await
.) Como alternativa, isso pode ser implementado como um analisador enviado como parte do tempo de execução.
Poderíamos flexibilizar a restrição de que os tipos de valores não podem ser lock
Lock
(necessário apenas se a proposta da API o alterou de class
para struct
),Poderíamos permitir a nova lock
nos async
métodos onde await
não é utilizado dentro do lock
.
lock
é reduzido para using
com um ref struct
como recurso, isso resulta em um erro em tempo de compilação.
A solução alternativa é extrair o lock
em um método nãoasync
separado.ref struct Scope
, poderíamos emitir os métodos Lock.Enter
e Lock.Exit
em try
/finally
.
No entanto, o método Exit
deve ser lançado quando é chamado de um thread diferente de Enter
, portanto, ele contém uma pesquisa de thread que é evitada ao usar o Scope
.using
em um ref struct
em métodos async
se não houver await
dentro do corpo using
.lock
Lock
+ adição de avisos de análise estáticaComentários do C# feature specifications
O C# feature specifications é um projeto código aberto. Selecione um link para fornecer comentários:
evento
Crie aplicativos e agentes de IA
17/03, 21 - 21/03, 10
Junte-se à série meetup para criar soluções de IA escaláveis com base em casos de uso do mundo real com outros desenvolvedores e especialistas.
Registe-se agora