Spinlock (Parte I)


Tenho recebido uma série de emails perguntando sobre SPINLOCK e infelizmente não tive tempo para escrever muito sobre o assunto. Há um post antigo: Spinlock Contention, mas vejo que falta mais coisa. Vou escrever esse artigo para dar uma idéia sobre o spinlock e, em seguida, mostrarei seu funcionamento.

Primeiro, devemos traduzir literalmente a palavra spinlock:

  • SPIN = Rodar
  • LOCK = Bloqueio

Isso dá uma pista inicial de que a estrutura de Spinlock corresponde a um lock na qual a thread fica rodando, muito semelhante a um loop infinito.

Em T-SQL, isso corresponde a um código assim:

SET LOCK_TIMEOUT 0

SpinLoop:
    
    UPDATE tabela SET coluna = 'bla'
    IF @@ERROR <>0 goto SpinLoop   

Analisando o código em uma situação na qual a tabela está bloqueada, observamos que esse código utiliza um LOOP INFINITO até que a tabela seja atualizada.

Meu experimento foi colocar um bloqueio propositalmente na tabela e em seguida rodar o SpinLock. O resultado foram 34074 mensagens repetidas como apresentadas abaixo, podendo dizer assim que houve 1 colisão e 34074 spins:

Msg 1222, Level 16, State 56, Line 3
Lock request time out period exceeded.
Msg 1222, Level 16, State 56, Line 3
Lock request time out period exceeded.
Msg 1222, Level 16, State 56, Line 3
Lock request time out period exceeded.
...
Msg 1222, Level 16, State 56, Line 3
Lock request time out period exceeded.

A vantagem desse código é que nenhum LOCK é efetivamente utilizado. Por outro lado, a CPU vai para 100% imediatamente.

O OBJETIVO DESSE CÓDIGO É ILUSTRAR A IDÉIA POR TRÁS DO SPINLOCK. JAMAIS USE ESTE CÓDIGO!

No próximo post, colocarei a descrição do “verdadeiro” spinlock.

Comments (6)

  1. Leivio disse:

    Olá Fabricio,

    Muito bom essa linha de post do Spinlock.

    Apenas para confirmar:

    O Spinlock seria uma consequencia do controle do acesso das regiões criticas pelas threads. Pelo conceito basico podemos extender para qualquer tipo de recurso em memoria(Fisica ou logica)?

    Tenho estudado bastante a parte de otimização de recursos em ambientes multi-processados(Acima de 32 cores) com SQL Server e como também tenho experiencia em desenvolvimento(C++) utilizando o API Windows tenho uma certa familiaridade com alguns conceitos. Analisando algumas descrições de recursos do SQLOS/UMS vejo alguns exemplos dos tipos de API utilizadas e isso ajuda bastante no entendimento de como o SQL Server funciona por dentro.

  2. Olá Leivio! Muito bom saber que você gosta de programar em C++.

    O spinlock é uma proteção de acesso concorrente de threads, exatamente como você falou. Ela existe no código do SQL Server, no Kernel do Windows, no Linux (com as pthreads), etc. Fazendo um paralelo com o Windows, veja a documentação da função InitializeCriticalSectionAndSpinCount em como funciona o parâmetro SpinCount.

    Existem várias formas de implementar um Spinlock. Recentemente, o SQL Server tem adotado um modelo de "exponential back-offs". Existem papers disponíveis no mundo acadêmico que discutem os ganhos disso tudo, mas dá uma olhada nesse artigo da Intel.

    software.intel.com/…/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architectures

    Espero que isso aumente sua curiosidade no assunto.

    Abraços, Fabricio

  3. DBA SQL disse:

    Muito interessante Fabrício. Se possível, podes demonstrar o SpinLock na prática? Tipo: mostrar quando ele pode gerar 100%¨CPU em um servidor SQL e como identificar possíveis problemas relativos ao mesmo?

    Abraço

  4. Aqui vai um exemplo (me corrijam se eu estiver errado ;-)): uma das estruturas no SQL Server que se beneficiam do spinlock é o campo IDENTITY. Uma thread que precisa pegar o próximo valor do identity e garantir que nenhuma outra thread concorrente irá ler o mesmo valor enquanto a primeira thread faz o incremento (condição de corrida), então o SQL Server protege o dado com um spinlock. Outra thread pode ficar bloqueada nesse pequeno intervalo não precisa ser tirada do processador e escalonada (pois ela está "girando") e eventualmente acessa o dado quando a thread 1 libera o acesso.

    Essa abordagem é mais eficiente do que implementarmos o nosso próprio identity em uma tabela de controle, onde seria necessário uma transação bloquear um registro com um lock exclusivo (e todo o seu custo inerente para alocação da estrutura), incrementar o valor e depois liberar o bloqueio. Em cenários com grande volume de transação vejo essa solução caseira trazendo problemas, pois é menos eficiente que o IDENTITY.

    Estou certo?

    E Leivio, excelentes comentários!

    []s

    Luti

  5. Valeu Luti! Bom falar com você!

    O exemplo do IDENTITY é um bom cenário, mas há um detalhe: todas as operações são logadas em disco e, por isso, o processo de incremento é feito usando um mecanismo de Latch. A idéia é isso mesmo!!! Um bom exemplo de Spinlock é na atualização dos contadores do Performance Monitor, no qual as variáveis são incrementadas de forma atômica. Qualquer sincronização que dura milissegundos utiliza Latches, enquanto que os mecanismos de nanossegundos usam spinlocks. Obrigado – Fabricio

  6. FonsecaSergio disse:

    Grande mestre Catae. Valeu pela explicação

Skip to main content