concorrencia101
  • Introdução
  • First things first
  • Agradecimentos
  • Parte I - Concorrência no sistema operacional
    • O que é o programa no sistema operacional
    • Escalonador preemptivo de tarefas
    • Uma nota sobre escalonamento cooperativo
    • Propriedades de um processo
    • Clone de processo (forking)
    • Clone leve de processo (thread)
    • Todo processo tem uma thread principal
    • Uma nota sobre paralelismo
    • Principais desafios em cenário de concorrência
      • Race condition
      • Sincronização com locks
      • Modelo de atores
    • E o I/O?
      • Latência de CPU vs Latência de I/O
      • Chamadas bloqueantes
      • Chamadas não-bloqueantes
      • Assincronismo e escalonamento cooperativo
    • Vamos colocar em prática...
  • PARTE II - Concorrência em diferentes linguagens
    • Definindo ambientes de execução
    • Concorrência em C
      • Forking de processos
      • Threads
      • Race condition e sincronização de threads com mutex
      • Desafios com o uso de threads
      • Thread Pool em C
      • Green threads
      • Modelo de Atores
      • Trabalhando com I/O
    • Concorrência em Ruby
      • Forking de processos
      • Threads
      • Race condition, YARV, GVL e paralelismo em Ruby
      • Modelo de Atores
      • Trabalhando com I/O
Powered by GitBook
On this page
  • Spinlock
  • Mutex
  1. Parte I - Concorrência no sistema operacional
  2. Principais desafios em cenário de concorrência

Sincronização com locks

PreviousRace conditionNextModelo de atores

Last updated 4 months ago

O sistema operacional fornece algumas primitivas para construção de mecanismos de sincronização (locks), como futex e instruções atômicas. Entretanto, essas primitivas são muito genéricas e requerem uma implementação mais robusta de lock, pois o Kernel obedece um design minimalista e tenta não impor nenhum mecanismo de lock, deixando que diferentes linguagens de programação possam implementar diferentes tipos de locks.

Vários tipos de locks podem ser implementados, mas vamos explicar brevemente o conceito de dois: spinlock e mutex.

Spinlock

Um lock baseado na técnica "busy-waiting", que é precisamente um loop onde a thread verifica o valor de uma variável compartilhada atomicamente. O spinlock não causa troca de contexto de threads, mas pode provocar um aumento do uso de CPU devido ao loop.

Mutex

Mutex refere-se a mutual exclusion, ou exclusão mútua, onde a thread é colocada em um estado de (wait) até que o recurso seja liberado por outra thread (wake). Isto pode ser implementado por meio de thread signaling, que são basicamente sinais que podemos enviar às threads.

A vantagem é que a CPU não é consumida durante o tempo de espera da thread, porém há uma latência maior devido à troca de contexto das threads. E também pode-se gerar um problema onde duas ou mais threads ficam bloqueadas pra sempre por conta de um lock mal utilizado ou "perdido", que se chama deadlock.

Com mutex, podemos fazer com que a thread que chegou primeiro tenha acesso exclusivo ao recurso. Qualquer outra thread que tentar acessar o mesmo recurso, seja pra leitura ou escrita, vai ter que esperar o lock ser liberado...

Existem outros tipos de locks, como semáforos e rwlocks, mas por enquanto vamos deixar apenas esses dois, pelo que na segunda parte do guia abordaremos em detalhes a implementação de locks em cada linguagem.


Entretanto, podemos implementar alternativas em cenários de concorrência de modo a evitar o uso de locks. Quando o compartilhamento de memória e uso de locks passa a ser um grande problema, uma alternativa é implementar algumas "peças" de concorrência onde o estado não é compartilhado e a comunicação entre diferentes peças passa a ser através do envio de mensagens. Estamos falando do modelo de atores.