UFRGS
C#
C#
UFRGS AutoriaAutoria �
Autores
�Cláudio Geyer �Local
�Instituto de Informática �UFRGS �disciplinas:� Programação Distribuída e Paralela
� Programação com Objetos Distribuídos
�Versão
UFRGS BibliografiaBibliografia
�
Bibliografia
�Robinson, Simon et al. Professional C#. Wrox, 2001. �Cursos em CD desenvolvidos/promovidos pela MS.
UFRGS SúmulaSúmula �
Súmula
�API �Primeiro exemplo: � criação � sleep�Estados de uma Thread �Exemplo com join
�Sincronização: exclusão mútua �Sincronização: classe Monitor
� classe
� wait e pulse
UFRGS Classe Thread: APIClasse Thread: API
�
Classe Thread: API
�o pacote System.Threading oferece recursos para a construção de threads
�a classe Thread e sua API
� métodos similares aos de Java Threads
� Start(): ativa uma thread
� Suspend(): suspende uma thread ativa
� Resume(): reativa uma thread suspensa
� Join(): espera pelo fim de uma thread
� Abort(): encerra a execução de uma thread
UFRGS Classe Thread: APIClasse Thread: API
�
Classe Thread: API
�métodos como Suspend(), Resume() e Abort()
� segundo MS, são métodos seguros
� não deixam thread em estado inconsistente
� Suspend()
� eventualmente algumas instruções da thread ainda são
executadas
UFRGS Classe Thread: APIClasse Thread: API
�
Classe Thread: API
�métodos como Suspend(), Resume() e Abort()
� Abort()
� lança execeção ThreadAbortException
� deve-se usar bloco try com cláusula finally
� em caso de abort, a cláusula finally será executada
� programador poderá realizar limpeza de recursos diversos
� thread não pode ser (re) ativada (start)
UFRGS Classe Thread: APIClasse Thread: API
Lista de métodos:
public sealed class Thread {}{
public static Thread CurrentThread { get; } } // static methods public static void Sleep(int milliSeconds) {...}
...
public Thread(ThreadStart startMethod) {...} // thread creation public string Name { get; set; } } // properties
public ThreadPriority Priority { get; set; } } public ThreadState ThreadState { get; } } public bool IsAlive { get; } }
public bool IsBackground { get; set; } } ...
public void Start() {...} // methods public void Suspend() {...}
public void Resume() {...}
public void Join() {...} // caller waits for the thread to die public void Abort() {...} // throws ThreadAbortException ...
UFRGS Classe Thread: APIClasse Thread: API
public delegate void ThreadStart(); // parameterless void method
public enum ThreadPriority {}{AboveNormal, BelowNormal, Highest, Lowest, Normal} public enum ThreadState {Aborted, Running, Stopped, Suspended, , Unstarted, ...}
Observações:
� Get: opção de leitura do atributo � Set: opção de escrita do atributo
UFRGS Especificação e Criação de ThreadEspecificação e Criação de Thread
�
Especificação do comportamento
�qualquer método (de qualquer classe) pode ser usado como comportamento (run em Java Threads) da thread
�
Criação: idéia
�cria-se um objeto Thread passando ao mesmo um método qualquer de um objeto qualquer
�concretamente o método é passado a um objeto auxiliar ThreadStart
UFRGS Especificação e Criação de ThreadEspecificação e Criação de Thread
�
Criação de objeto Thread
�construtor da classe Thread, do pacote System.Threading
� public Thread(ThreadStart startMethod) {...}
� argumento: objeto ThreadStart
�construtor da classe ThreadStart
� public ThreadStart(runMethod)
� runMethod: na forma object.method
� object: de qualquer classe
� method: qualquer
UFRGS Ativação da ThreadAtivação da Thread
�
Ativação da Thread
�método Start:
� public void Start()
� objeto deve ser da classe Thread
� método não bloqueante
UFRGS Primeiro Exemplo: 2 threadsPrimeiro Exemplo: 2 threads
�
Primeiro exemplo: 2 threads
�programa cria 2 threads da classe Printer �método comportamento: Print
�classe Printer
� construtor
� recebe 2 argumentos
� 1 caracter
� 1 tempo para dormir
� método Print
� loop de 1 a 100
UFRGS ExemploExemplo using System; using System.Threading; class Printer { char ch; int sleepTime;
public Printer(char c, int t) {ch = c; sleepTime = t;} public void Print() {
for (int i = 0; i < 100; i++) { Console.Write(ch);
Thread.Sleep(sleepTime); // método de classe }
} }
class Test {
static void Main() {
Printer a = new Printer('.', 10); Printer b = new Printer('*', 100);
new Thread(new ThreadStart(a.Print)).Start(); // a.Print: arg. de ThreadStart new Thread(new ThreadStart(b.Print)).Start(); // Start: sobre objeto Thread }
}
// programa executa até as 2 threads terminarem
UFRGS Estados de uma ThreadEstados de uma Thread
�
Estados de uma Thread
�Unstarted
� logo após ser criada (antes do Start() )
�Running
� após ser ativada (Start() )
� após método Resume()
� Suspended
� após método Suspended()
�Stopped
� após método Abort()
UFRGS Estados de uma ThreadEstados de uma Thread
Thread t = new Thread(new ThreadStart(P)); // P: método da classe/objeto atual Console.WriteLine("name={0}, priority={1}, state={2}", t.Name, t.Priority,
t.ThreadState);
t.Name = "Worker"; t.Priority = ThreadPriority.BelowNormal; t.Start();
Thread.Sleep(0); // garante o novo estado
Console.WriteLine("name={0}, priority={1}, state={2}", t.Name, t.Priority, t.ThreadState); t.Suspend(); Console.WriteLine("state={0}", t.ThreadState); t.Resume(); Console.WriteLine("state={0}", t.ThreadState); t.Abort(); Thread.Sleep(0); Console.WriteLine("state={0}", t.ThreadState); Output
name=, priority=Normal, state=Unstarted
name=Worker, priority=BelowNormal, state=Running state=Suspended
UFRGS PrioridadesPrioridades
�
Prioridades de uma thread
�válidas dentro do processo que contem a thread
� nenhuma relação entre prioridades de threads de processos
distintos
�uma thread com prioridade mais baixa só recebe cpu
� se as threads de prioridade mais alta estiverem bloqueadas
� observação: threads do mesmo processo
�aplicação
� garantir que thread de atendimento a usuário tenha tempo de
resposta rápido (“imediato”)
UFRGS Método JoinMétodo Join
�
Método Join
�função
� esperar pelo fim de uma thread
� método bloqueante
�opção
� esperar até certo tempo (argumento)
�Exemplo (aseguir)
� thread Main espera pelo final da thread Test
UFRGS Exemplo com joinExemplo com join
using System;
using System.Threading;
class Test {
static void P() {
for (int i = 1; i <= 20; i++) { Console.Write('-');
Thread.Sleep(100); }
}
static void Main() {
Thread t = new Thread(new ThreadStart(P)); Console.Write("start");
t.Start(); t.Join();
Console.WriteLine("end"); }
UFRGS Sincronização: exclusão mútuaSincronização: exclusão mútua
�
Sincronização: exclusão mútua
�comando lock
� formato
� lock(Variable) Statement
� Variable: de qualquer classe
� Statement: simples ou bloco ({...})
UFRGS Sincronização: exclusão mútuaSincronização: exclusão mútua
�
Sincronização: exclusão mútua
�comando lock
� semântica
� similar ao lock (mutexbegin/end) tradicional
� inicialmente lock está livre (aberto)
� primeira thread a passar pelo lock
� atomicamente coloca o lock em fechado
� enquanto lock fechado
� outras threads ficarão bloqueadas até lock ser
aberto
UFRGS Sincronização: exclusão mútuaSincronização: exclusão mútua
�
Example
�Esqueleto de classe conta bancária
�class Account { // this class should behave like a monitor
long val = 0;
public void Deposit(long x) {
// only 1 thread at a time may execute this statement
lock (this) { val += x; } }
public void Withdraw(long x) { lock (this) { val -= x; } }
UFRGS Classe MonitorClasse Monitor
�
Classe Monitor
�lock(v) Statement
é uma abreviação para bloco de c
Monitor.Enter(v); try { Statement } finally { Monitor.Exit(v); }
�A classe Monitor possui 2 métodos
UFRGS Classe MonitorClasse Monitor
�
Classe Monitor
�o bloco try-catch com finally
� garante que o unlock (Monitor.Exit), ou mutexend, será
sempre executado
UFRGS Wait e PulseWait e Pulse
�
Wait e Pulse
�métodos da classe Monitor �semântica clássica
� primitivas Wakeup e Signal dos monitores
� objetos lockedVar (ver abaixo) comportam-se como variáveis
de condição
UFRGS Wait e PulseWait e Pulse
�
Wait e Pulse
�Monitor.Wait(lockedVar)
� bloqueia chamador incondicionalmente
� similar a wait() de Java
�Monitor.Pulse(lockedVar)
� acorda uma thread bloqueada em lockedVar
� similar a notify() de Java Threads
�Monitor.PulseAll(lockedVar)
� acorda todas as threads bloqueadas em lockedVar
UFRGS Wait e PulseWait e Pulse
� Descrição
� “A” chega no lock e prossegue porque o lock está livre
� “B” chega no lock e fica bloqueado porque o lock está preso
� “A” bloqueia-se ao chamar o método Wait(), liberando o lock
� “B” prossegue pois o agora o lock está aberto
� “B” acorda “A” com o método Pulse()
� “A” tenta obter o lock, mas falha pois “B” ainda está com ele
Thread A Thread B lock(v) { lock(v) { ... ... Monitor.Wait(v); Monitor.Pulse(v); ... ... } }
UFRGS QuestõesQuestões
�
Questões
�Qual a semântica do Pulse e PulseAll com relação ao lock, isto é, quem fica com o lock? O acordado ou o que acorda?
�Quem é acordado entre os que estão dormindo? Fila FIFO? Ou qualquer um?
�A fila de entrada no lock é FIFO?
�A variável (objeto) do Wait e do Pulse pode ser diferente da variável do lock?
UFRGS Exemplo: buffer sincronizadoExemplo: buffer sincronizado
� Exemplo: buffer sincronizado
� Problema clássico do produtor/consumidor
� uma classe que implementa um servidor de buffer
� atributos
� principal: um buffer de caracteres � tamanho finito
Buffer
Cliente 1 Cliente 2 Cliente 3
Put(“A”) C = Get()
UFRGS Exemplo: buffer sincronizadoExemplo: buffer sincronizado
�
Exemplo: buffer sincronizado
�API
� método Put()
� clientes colocam 1 char no buffer
� caso buffer cheio, cliente deve ficar bloqueado
� aguarda 1 Get() (ver abaixo)
� método Get()
� clientes retiram 1 char do buffer
� caso buffer vazio, cliente deve ficar bloqueado
UFRGS Exemplo: buffer sincronizadoExemplo: buffer sincronizado
�
Exemplo: buffer sincronizado
�implementação
� Put() e Get()
� seção crítica (lock) cobre todo o código do método
� cada um acorda o outro via o Pulse()
� incondicionalmente
� Pulse() é não bloqueante
� sinal é perdido se ninguém está bloqueado
� Put()
� cliente dorme via Wait()
UFRGS Exemplo: buffer sincronizadoExemplo: buffer sincronizado
�
Exemplo: buffer sincronizado
�implementação
� Get()
� cliente dorme via Wait()
� caso buf vazio: n igual a zero
UFRGS Exemplo: buffer sincronizadoExemplo: buffer sincronizado
class Buffer {
const int size = 4;
char[] buf = new char[size]; int head = 0, tail = 0, n = 0; public void Put(char ch) {
lock(this) {}{
while (n == size) Monitor.Wait(this);
buf[tail] = ch; tail = (tail + 1) % size; n++; Monitor.Pulse(this);
} }
public char Get() { lock(this) {}{
while (n == 0) Monitor.Wait(this);
char ch = buf[head]; head = (head + 1) % size; n--; Monitor.Pulse(this); return ch; } If producer is faster Put Put Put Put Get Put Get ... If consumer is faster Put Get Put Get ...
UFRGS DesempenhoDesempenho
�
Comparação Java X C#
�ênfase no desempenho de métodos básicos �resultados similares
�em alguns casos, vantagem para Java �por Rodrigo Luque, aluno do CIC-UFRGS
UFRGS DesempenhoDesempenho
�
Comparação C/Posix X C#
�3 trabalhos em SOII, 2010-2
� Comparação de desempenho
� Criação e join, mutex e semáforo
� C/Posix x C#
� Em 1 TF: C em Linux Ubuntu e C# em Windows 7
UFRGS ResumoResumo
�
Resumo
�Pacote Threading �Classe Thread
�Atributos similares aos de Java
� Prioridade
� Nome
�Métodos similares aos de Java
� Start, Join, Sleep, ...
�Criação
� Somente por instanciação
� Comportamento dado por método qualquer passado na
UFRGS ResumoResumo
�
Resumo
�Sincronização
� Por conceito de monitor
� Bloco “lock”
� Similar ao bloco synchronized de Java
� Oferece exclusão mútua
� Sinalização
� Por “wait/pulse”
� Similar a “wait/notify” de Java
UFRGS ExercíciosExercícios
�
Exercícios
�1) Compare os pacotes de threads para Java e C#: ao menos 3 itens com diferenças e 2 com similaridades
�2) Exemplo Buffer: analise o comportamento do sistema caso o número de clientes seja maior que 2
� 2 ou mais produtores (Put())
��������������������������������������������������������������������������������� �����������������������������������������������������