construtor de instância define um membro estático, não é thread-safe?

votos
5

Estou re-factoring algum código e estou querendo saber sobre o uso de um lockno construtor de instância.

public class MyClass {

    private static Int32 counter = 0;
    private Int32 myCount;

    public MyClass() {

        lock(this) {
            counter++;
            myCount = counter;
        }
    }
}

Por favor confirme

  1. construtores de instância são thread-safe.
  2. A declaração de bloqueio impede o acesso a esse bloco de código, não para a 'contra' membro estático.

Se a intenção do programador original era ter cada instância saber sua 'contagem', como eu sincronizar o acesso ao membro balcão para garantir que outro segmento não é new'ing um MyClasse mudando a contagem antes deste define sua contagem?

FYI - Esta classe não é um singleton. Instâncias deve simplesmente estar ciente de seu número.

Publicado 03/09/2008 em 15:28
fonte usuário
Em outras línguas...                            


7 respostas

votos
12

Se você só está incrementando um número, há uma classe especial (Encaixado) para que ...

http://msdn.microsoft.com/en-us/library/system.threading.interlocked.increment.aspx

Método Interlocked.Increment

Incrementa uma variável especificada e armazena o resultado, como uma operação atômica.

System.Threading.Interlocked.Increment(myField);

Mais informações sobre enfiar as melhores práticas ...

http://msdn.microsoft.com/en-us/library/1c9txz50.aspx

Respondeu 03/09/2008 em 15:53
fonte usuário

votos
4

Eu estou supondo que isto é para um padrão singleton ou algo parecido. O que você quer fazer é não bloquear o seu objeto, mas bloquear o balcão enquanto você está modificando-o.

private static int counter = 0;
private static object counterLock = new Object();

lock(counterLock) {
    counter++;
    myCounter = counter;
}

Porque o seu código atual é uma espécie de redundante. Especialmente sendo no construtor, onde há apenas um segmento que pode chamar um construtor, ao contrário de métodos onde poderia ser compartilhados entre threads e ser acessado a partir de qualquer segmento que é compartilhado.

Do pouco que eu posso dizer de você código, você está tentando dar o objeto a contagem atual no momento de ele ser criado. Assim, com o código acima o contador será bloqueada enquanto o contador é atualizado e definido localmente. Então, todos os outros construtores terão que esperar para o contador para ser liberado.

Respondeu 03/09/2008 em 15:33
fonte usuário

votos
3

@ajmastrean

Não estou dizendo que você deve usar o próprio padrão Singleton, mas adotar seu método de encapsular o processo de instanciação.

ou seja

  • Faça o construtor privado.
  • Criar um método de instância estática que retorna o tipo.
  • No método de instância estática, use a palavra-chave bloqueio antes de instanciar.
  • Instanciar uma nova instância do tipo.
  • Incrementar a contagem.
  • Desbloquear e retornar a nova instância.

EDITAR

Um problema que ocorreu-me, se como você sabe quando a contagem foi para baixo? ;)

EDIT nOVAMENTE

Pensando nisso, você pode adicionar código para o destruidor que chama outro método estático para diminuir o contador: D

Respondeu 03/09/2008 em 15:41
fonte usuário

votos
3

Você pode usar outro objeto estático para bloquear nele.

private static Object lockObj = new Object();

e bloquear este objecto no construtor.

lock(lockObj){}

No entanto, eu não tenho certeza se há situações que devem ser tratadas por causa da otimização do compilador em .NETcomo no caso de java

Respondeu 03/09/2008 em 15:34
fonte usuário

votos
2

A maneira mais eficiente de fazer isso seria usar a operação de incremento Interlocked. Ele vai incrementar o contador e retornar o novo valor definido do contador estática de uma só vez (atomicamente)

class MyClass {

    static int _LastInstanceId = 0;
    private readonly int instanceId; 

    public MyClass() { 
        this.instanceId = Interlocked.Increment(ref _LastInstanceId);  
    }
}

No seu exemplo original, o bloqueio (this) declaração não terá o efeito desejado porque cada instância individual terá um "presente" de referência diferente, e várias instâncias poderia, assim, estar atualizando o membro estático, ao mesmo tempo.

Em certo sentido, construtores pode ser considerado para ser thread-safe porque a referência para o objeto que está sendo construído não é visível até que o construtor foi concluída, mas isso não faz qualquer bom para proteger uma variável estática.

(Mike Schall teve o bit intertravado primeiro)

Respondeu 03/09/2008 em 16:42
fonte usuário

votos
0

@ Rob

FYI, Esta classe não pode ser um solteirão, eu preciso de acesso a diferentes instâncias. Eles devem simplesmente manter uma contagem. Que parte do padrão Singleton que você mudaria para executar 'balcão' incrementando?

Ou você está sugerindo que eu expor um método estático para a construção bloqueando o acesso ao código que incrementa e lê o contador com um bloqueio.

public MyClass {

    private static Int32 counter = 0;
    public static MyClass GetAnInstance() {

        lock(MyClass) {
            counter++;
            return new MyClass();
        }
    }

    private Int32 myCount;
    private MyClass() {
        myCount = counter;
    }
}
Respondeu 03/09/2008 em 15:37
fonte usuário

votos
0

Eu acho que se você modificar o padrão Singleton para incluir uma contagem (obviamente usando o método de thread-safe), você vai ficar bem :)

Editar

Porcaria que eu acidentalmente apagado!

Não tenho a certeza se a instância construtores SÃO thread-safe, eu lembro de ter lido sobre isso em um livro de padrões de projeto, você precisa garantir que os bloqueios estão no lugar durante o processo de instanciação, puramente por causa disso ..

Respondeu 03/09/2008 em 15:35
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more