2. Processos vs Threads
Processos são containers mapeados para um endereço de memoria no
qual outros processos não tem permissão de leitura
Memoria Processos
3. Threads
Roda todo ou parte do código dentro de um
processo
Tem acesso a um pedaço ou toda memoria
mapeada para o processo
Toda thread tem sua propina copia da
callstack e registradores da CPU.
Um processo sem nenhuma thread é
finalizado, já que não esta realizando nenhum
execução.
4. Vantagens do uso de multi-threading
Possibilidade de escalar as operações da CPU a partir de paralelização de
processamento de dados (assumindo um hardware com multi-core/multi-
processadores)
Realizar operações variadas enquanto esperamos por operações de I/O
finalizem.
Manter uma UI responsiva
5. Preocupações com muti-threading
Adiciona complexidade ao programa
Linhas de código
Leitura
Testabilidade
Execução mais lenta em maquinas com
um core ou processador
9. Tempo de vida de uma thread
Uma thread para quando
O método da thread retorna
Ocorre um exception não tratada (synchronous exception)
Outra thread para ela com “Interrupt”ou “Abort” (asynchronous exception)
A propriedade IsAlive prove um snapshot instantaneo do status da thread
IsAlive == false
10. Como parar uma thread?
Idealmente é ter uma logica pré-definida para abortar a execução
11. Thread-pool
Prove uma forma em que as threads são
emprestadas para operações
concorrentes que sejam rápidas.
CLR prove uma thread-pool por
processo.
Threads são adicionadas ou removidas
de acordo com a demanda
Permite que o custo de criar e matar
threads seja reduzido durante a vida do
processo
Por padrão tem a propriedade
IsBackground definida como `true`
Usado de implicitamente forma padrão
ao utilizar Async I/O, Delegate.Invoke,
Parallel.For, PLINQ
14. ThreadLocal State
Com isso seu programa instancia mais de 100 WebClients, seu programa lança uma exceção que
informa que seus webclients estão dando timeout. Você percebe que é porque sua máquina não
está executando um sistema operacional de servidor, e há um limite máximo no número de
conexões simultâneas.
15. ThreadLocal State
Nesse caso, cada operação de acesso a dados é inteiramente independente um do outro.
O uso do thread-local state nos permitiu garantir que gerássemos apenas tantos objetos
WebClient quanto necessário, e que cada WebClient pertence a thread que o gerou.
16. ThreadLocal State
O mesmo é conseguido com PLINQ utilizando o ThreadLocal<>, porém é importante ressaltar
que, em qualquer cenário, usando o tipo ThreadLocal<> é mais custoso do que usar o overload
de ThreadLocalState do Parallel.ForEach
17. Sincronização de threads
A maior parte dos recursos dentro de um programa não são pensados
para serem usados de forma concorrente.
Collections (array, list, dictionary, etc)
Files
Mesmo inteiros
Oque deveria ser exibido?
Oque será exibido?
18. Sessões criticas
Uma sessão critica é uma região do código que ira acessar um recurso
compartilhado:
22. Solução 3: Wait Based Synchronization
Quando threads necessitam de acessar o mesmo recurso que não pode ser
particionado (adicionar ou remover um no de uma lista, ou manipular o
mesmo arquivo)
Algumas vezes queremos que uma thread esteja block ate algum evento
ocorrer.
A casos que os dados dependem de um passo anterior inviabilizando
particionamento.
Quando o input de uma thread depende do output de outra
Calcular a sequencia de Fibonacci
Sequence[0] = Sequence[1] = 1
Sequence[n] = Sequence[n-1]+Sequence[n-2]
24. Wait-Based Thread Synchronization
Primitives
Existem vários primitivos para controle de threads no CLR
System.Threading:
Monitor
Mutex
ReaderWriterLockSlim
ManualResetEvent, AutoResetEvent
Semaphore, SlimSemaphore
Os 3 primeiros compartilham o mesmo modelo de uso:
Faz uma chamada para adquirir o owner do “lock”
Usa o recurso compartilhado que o “lock” designado visa proteger
Faz um chamada para liberar o “lock” assim que o recurso não é mais
necessário
25. System.Threading.Monitor
Monitor garante acesso exclusivo a um recurso
CLR permite apenas uma thread entrar no contexto do
monitor por vez
Outras threads que tentarem entrar irão ficar bloqueada
Assim que o recurso for liberado a próxima thread na
espera ira adquirir para si o acesso exclusivo ao recurso
26. Monitors no CLR
Metodos do monitor operam em cima de uma referencia de um objeto
Qualquer referencia de objeto no HEAP pode potencialmente ser associado a
um lock
29. Hold & Wait
As vezes uma thread precisa e esperar alguma coisa enquanto segura um
lock
Em scenarios de producer/consumer é comum ter que lidar com
gerenciamento de disponibilidade de recursos.
Mutipla aquisição de locks
34. DEADLOCK
Deadlocks podem ocorrer a qualquer momento em que esteja numa
situação de Hold & Wait
Enquento segura um lock a thread tenta obter outro lock
Deadlocks podem ocorrer mas não necessariamente vão ocorrer
Deadlocks são possíveis mas não necessariamente prováveis (a probabilidade
aumenta de acordo com o # de threads/processadores/cores)
Deadlock podem talvez ser temporário caso seja utilizado timeouts nas aquisições
de lock
36. Mutexes
Um Mutex é um objeto de Kernel (Sytem.Threading.Mutex)
Suporta timeout em aquisições de lock
Nomeável, permite sincronização cross-process na mesma maquina
Habilita o uso múltipla aquisições de lock com de deadlock-free via
WaitHandle.WaitAll
Tradeoffs
Chamadas de aquisições e liberação de locks sempre ocorrem em kernel mode
Objetos de kernel devem ser fechados assim que não mais necessários (ocorre
automaticamente mas depende do GC)
39. Semaphore
Funciona de forma similar ao Monitor ou Mutex, porem ele delimita
quantas threads podem acessar uma sessão critica ao mesmo tempo.
É como uma balada como uma fila, aonde as pessoas na fila esperam uma
pessoa sair da balada para entrar.
System.Threading.SemaphoreSlim é mais leve, não faz chamdas de kernel, para
ser usado em apenas um processo.
System.Threading.Semaphore pode ser nomeado e funciona entre processos
Não tem garantia de ordem
41. ReaderWriterLockSlim
Possui trem modos : Read, Write e Ungradeable
Muitas threads podem estar simutaneamente em modo Read
Apenas uma pode entrar em modo Ungradeable mas outras threads
podem entrar em modo read
Apenas uma Thread pode entrar em modo write, e nenhuma outra thread
pode adquirir um lock
44. Keyword : volatile
Não reordena instruções na memoria
“Garante” que a leitura do valor mais novo será realizada
Resolvia o problema de double null check em versões do .NET < 2
Deve ser evitado
Apenas utilizado em casos em que o cenario de locks não esta atendendo
a performance desejada
45. E o TPL? Async await?
IMPORTANTE: Assíncrono não é equivalente a paralelo.
A classe Task ou ValueTask não necessariamente estão vinculadas com
threads.
O Método estático Task.Run() ou Task.Factory.StartNew() sempre inicia
uma thread, e é a forma recomendada para se criar threads no .NET
moderno.
Mais sobre isso na proxima, sobre .NET Assincrono