MAC 441/5714 - Tópicos de Programação
Orientada a
Objetos
Aula 27 - 24/06/2004
Processos
- Em Smalltalk, há dois tipos de processos:
- Processos Internos
- representa uma linha de execução que roda
dentro de um processo do SO; ou seja, ao criar um novo processo interno
não estamos criano um novo processo do SO.
- é representado por instâncias da classe Process.
- Processos Externos
- representa um processo nativo do SO
- é representado por instâncias da classe UnixProcess que é
subclasse de ExternalProcess
Processos Internos
- A classe ProcessorScheduler
é um singleton cuja instância é armazenada na
variável global Processor
que é responsável pelo escalonamento dos processos
internos.
- Cada processo tem uma prioridade e o escalonador sempre executa o
processo de maior prioridade.
- A execução de um processo só é
interrompida quando um processo de maior prioridade é ativado ou
quando alguém envia uma mensagem (p.ex., pause, suspend, yield) forçando
explicitamente sua parada.
- A forma mais simples de se criar um processo é enviando a
mensagem fork a um bloco.
Neste caso, o bloco cria um Process
passando self como
parâmetro. É então criado um novo processo com a
mesma prioridade do processo corrente.
- Exemplo:
- coleção :=
#(1 2 3 4 5 6 7 8 9 10).
[coleção do:
[:elemento | Transcript show: (elemento printString)]] fork.
- Podemos também criar um novo processo através da
mensagem newProcess mas aí é necessário depois
ativar o processo:
- proc := [Transcript show: (1000 factorial) / (999 factorial)]
newProcess.
proc resume.
- Já o newProcessWithArguments
recebe como parâmetro um Array contendo os parâmetros que
deverão ser passados ao bloco.
- Note que o escalonador do Smalltalk não é
"preemptivo", ou seja, se tivermos vários processos com mesma
prioridade prontos para serem executados, eles não serão
executados concorrentemente mas sim seqüencialmente.
- Se o programador quiser concorrência, ele pode usar um dos
seguintes métodos:
- Process>>yield
cede a execução para outro processo de mesma prioridade. Processor>>yield faz com
que o Processor repasse a
mensagem yield para o
processo em execução.
- O exemplo seguinte do uso do yield não resultou no
efeito esperado no meu VW 7.2 no MacOS X:
- [50 timesRepeat: [Transcript
show: '/'. Processor yield]] fork.
[50 timesRepeat: [Transcript show: '\'. Processor yield]] fork.
- dou um chocolate para o aluno que descobrir o porquê.
- Na classe Delay
temos forMilliseconds: , forSeconds: criam uma
instância de Delay;
para realmente esperar, é necessário enviar a mensagem wait ao objeto do tipo Delay.
- untilMilliseconds:
após o envio de um wait,
dorme até que o relógio do sistema atinja o
instante especificado.
- Exemplo:
- [500 timesRepeat:
[Transcript show: '-'. (Delay forMilliseconds: 10) wait]] fork.
[400 timesRepeat:
[Transcript show: '|'. (Delay forMilliseconds: 10) wait]] fork.
- Um processo pode ser retirado da fila de processos agendados
através da mensagem suspend.
- p := Process
forBlock: [1 to: 50 do:
[:cont |
Transcript show: (cont printString, ' ' ).
(Delay forMilliseconds: 100) wait]]
priority: 50.
p resume.
(Delay forSeconds: 2) wait.
p suspend.
[10 timesRepeat:
[Transcript show: 'Processo 2!!!']] fork.
p resume.
- A mensagem terminate
é usada para retirar um processo do escalonador (Processor): (note a nova forma de criar um processo):
- p := Process
forBlock: [1 to: 1000 do:
[:cont | Transcript show: (cont printString, ' ' ).
(Delay
forMilliseconds: 100) wait]]
priority: 51.
p resume.
(Delay forSeconds: 3) wait.
p terminate.
- As prioridades determinam quais processos devem ser executados em
cada instante.
- Em Smalltalk, prioridades variam de 1 a 100. A classe ProcessorScheduler define os
seguintes métodos que devolvem números de acordo como
nome da mensagem:
- 1: systemRockBottonPriority
para processos de muito pouca importância
- 10: systemBackgroundPriority
- 30: userBackgroundPriority
- 50: userSchedulingPriority
é a prioridade padrão usada no fork
- 70: userInterruptPriority
usado, por exemplo, no sistema de gerenciamento de janelas
- 90: lowIOPriority
para processos de E/S de dispositivos como mouse e teclado
- 98: highIOPriority
para processos de E/S de dispositivos como disco e rede
- 100: TimingPriority
para processos de tempo real
Comunicação entre Processos: Filas Compartilhadas
- A forma mais comum de comunicação entre
processos em Smalltalk são as filas compartilhadas.
- Objetos do tipo SharedQueue atuam como canais de
comunicação entre dois ou mais processos.
- A comunicação entre os processos é
sincronizada através do uso de semáforos.
- Em geral, um dos processos atua como produtor e usa a mensagem nextPut: umObjeto para enviar
objetos através da fila
- e o outro processo atua como um consumidor e usa a mensagem next para extrair os objetos da
fila.
- Se a fila está vazia o next causa a suspensão
do processo até que haja algo para se retirar da fila.
- Exemplos:
- fila := SharedQueue new.
consumidor := [ [true]
whileTrue: [Transcript show: (fila next printString), ' ']] fork.
[1 to: 100 do: [:cont |
(cont odd) ifTrue: [fila nextPut:cont]. Processor yield ].
consumidor
terminate.] fork.
- fila := SharedQueue new.
consumidor := [[true]
whileTrue: [Transcript show: (fila next printString), ' ']] fork.
[1 to: 100 do: [:cont |
(cont odd) ifTrue: [fila nextPut:cont]. (Delay forMilliseconds: 100)
wait. ].
consumidor
terminate.] fork.
- note que sem o yield
ou o delay, o consumidor
não consegue consumir nada.
- fila size pode ser
utilizado para se determinar o número de objetos da fila.
- fila peek devolve
o objeto no começo da fila sem retirá-lo de lá.
Comunicação entre Processos: Semáforos
- Além das filas compartilhadas, processos também
podem ser sincronizados através de semáforos.
- Como em SOs, semáforos permitem que um processo p1
sinalize que outro processo p2 pode voltar a executar.
- Em geral, semáforos estão associados a um recurso
(físico ou lógico) e os processos compartilhando aquele
recurso usam o semáforo para controlar o acesso a ele.
- Um processo espera num semáforo com wait e sinaliza com signal. Exemplo:
- |nome|
sinaleiro := Semaphore new.
p1 := Process forBlock: [5
timesRepeat: [sinaleiro wait. Transcript cr; show: nome]]
priority:50.
p2 := Process forBlock: [5
timesRepeat: [nome := Dialog request: 'Qual seu nome?'.
sinaleiro signal.]]
priority: 50.
p1 resume.
p2 resume.
- Se vários processos dão um wait no mesmo semáforo
eles são incluidos numa fila e reativados em ordem FIFO a cada
novo signal.
Execução de Processos Externos
- No Unix:
- UnixProcess forkJob:
'/Applications/iTunes.app/Contents/MacOS/iTunes' arguments: nil
- UnixProcess cshOne: 'ls -ls'
- No Windows:
- Win32SystemSupport
CreateProcess: 'C:\winnt\notepad.exe' aruments: nil
Referências
- Daniel D. Abdala e Aldo v. Wangenheim. Conhecendo o Smalltalk.
Capítulo 10.
- (há alguns errinhos neste capítulo)
Aula Anterior
Página de MAC 5714
Página do Fabio
Página do DCC