bloqueio duplo-check-in .NET
-
23-08-2019 - |
Solução
implementar o padrão Singleton em negociações C # sobre este problema na terceira versão.
Ele diz:
Fazendo a variável de instância volátil pode fazê-lo funcionar, como seria chamadas de barreira memória explícita, embora neste último caso até mesmo especialistas não conseguem concordar exatamente qual as barreiras são necessárias. I tendem a tentar situações Evitar onde especialistas não concordam que é certo eo que é errado!
O autor parece implicar que bloqueio duplo é menos provável de trabalho do que outras estratégias e, portanto, não deve ser utilizado.
Outras dicas
duplo controlo bloqueio agora trabalha em Java, bem como C # (o modelo de memória Java mudou e este é um dos efeitos). No entanto, você tem que obtê-lo exatamente direita. Se você bagunçar as coisas mesmo que ligeiramente, você pode muito bem acabar por perder a segurança do thread.
Como outras respostas afirmaram, se você está implementando o href="http://pobox.com/~skeet/csharp/singleton.html" rel="noreferrer"> singleton padrão lá são muito melhores maneiras de fazer isso. Pessoalmente, se eu estou em uma situação onde eu tenho que escolher entre bloqueio duplo verificado e "bloquear sempre" código de eu ir para o bloqueio cada vez que até eu tenho evidência real de que ele estava causando um gargalo. Quando se trata de threading, um simples e obviamente correto padrão vale muito.
.NET 4.0 tem um novo tipo: Lazy<T>
que tira qualquer preocupação sobre como obter o errado padrão. É parte da nova biblioteca paralela de tarefas.
Veja o MSDN computação paralela Dev Center: http://msdn.microsoft. com / en-us / simultaneidade / default.aspx
BTW, há um backport (creio que não é suportado) para .NET 3.5 SP1 disponível aqui .
Note que em Java (e, provavelmente, na Net também), com verificação dupla de bloqueio para inicialização singleton é completamente desnecessário, bem como quebrado. Como as classes não são inicializados até que eles são utilizados pela primeira vez, a inicialização lenta desejada já esteja garantido por este;
private static Singleton instance = new Singleton();
A menos que sua classe Singleton contém coisas como constantes que podem ser acessados ??antes de uma instância Singleton é utilizado pela primeira vez, isso é tudo que você precisa fazer.
Eu não entendo por que todas as pessoas diz que o bloqueio duplo-check é ruim padrão, mas não adaptar o código para que ele funcione corretamente. Na minha opinião, este código abaixo deve funcionar muito bem.
Se alguém poderia me dizer se este código sofrem com o problema mencionada no artigo de Cameron, por favor.
public sealed class Singleton {
static Singleton instance = null;
static readonly object padlock = new object();
Singleton() {
}
public static Singleton Instance {
get {
if (instance != null) {
return instance;
}
lock (padlock) {
if (instance != null) {
return instance;
}
tempInstance = new Singleton();
// initialize the object with data
instance = tempInstance;
}
return instance;
}
}
}
Eu comecei com verificação dupla de bloqueio para o trabalho usando um boolean (ou seja, usando um primitivo para evitar a inicialização preguiçoso):
O singleton usando boolean não funciona. A ordem das operações, como visto entre os diferentes tópicos não é garantida a menos que você passar por uma barreira de memória.
Em outras palavras, como visto de um segundo segmento,
created = true
pode ser executado antes instance= new Singleton();
Eu não entendo muito bem porque há um monte de padrões de implementação de bloqueio com verificação dupla (aparentemente para trabalho em torno de idiossincrasias do compilador em várias línguas). O artigo da Wikipedia sobre este tópico mostra o método ingênuo e as possíveis maneiras de resolver o problema, mas nenhum é tão simples como isto (em C #):
public class Foo
{
static Foo _singleton = null;
static object _singletonLock = new object();
public static Foo Singleton
{
get
{
if ( _singleton == null )
lock ( _singletonLock )
if ( _singleton == null )
{
Foo foo = new Foo();
// Do possibly lengthy initialization,
// but make sure the initialization
// chain doesn't invoke Foo.Singleton.
foo.Initialize();
// _singleton remains null until
// object construction is done.
_singleton = foo;
}
return _singleton;
}
}
Em Java, você pode usar sincronizado () em vez de bloqueio (), mas é basicamente a mesma idéia. Se há a possível inconsistência quando o campo singleton é atribuído, então por que não usar uma variável com escopo localmente em primeiro lugar e, em seguida, atribuir o campo singleton no último momento possível antes de sair da seção crítica? Estou faltando alguma coisa?
Há o argumento @ michael-Borgwardt que em C # e Java do campo estático só é inicializado uma vez no primeiro uso, mas que comportamento é específico da linguagem. E eu usei esse padrão com freqüência para a inicialização lenta de uma propriedade de coleção (por exemplo user.Sessions).
Eu comecei com verificação dupla de bloqueio para o trabalho usando um boolean (ou seja, usando um primitivo para evitar a inicialização preguiçoso):
private static Singleton instance;
private static boolean created;
public static Singleton getInstance() {
if (!created) {
synchronized (Singleton.class) {
if (!created) {
instance = new Singleton();
created = true;
}
}
}
return instance;
}