MAC 441/5714 - Tópicos de Programação
Orientada a
Objetos
Aula 23 - 12/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 criando um novo processo do SO.
- é representado por instâncias da classe Process. A
documentação desta classe no squeak diz o seguinte:
- Process represents an
independent path of control in the system. This path of control may be
stopped (by sending the message suspend) in such a way that it can later be
restarted (by sending the message resume). When any one of several paths of control
can be advanced, the single instance of ProcessorScheduler named Processor determines which one will actually be
advanced partly using the value of priority.
- Processos Externos
- representa um processo nativo do SO
- No VisualWorks é representado por instâncias da
classe UnixProcess que
é
subclasse de ExternalProcess
- No squeak é representado por instâncias da
classe OSProcess e possui
subclasses para inúmeros sistemas operacionais.
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, terminate)
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 newProcessWith
(newProcessWithArguments no VW) 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:
- Processor>>yield
cede a execução para outro processo de mesma prioridade.
- O exemplo seguinte do uso do yield não resultou no
efeito esperado no meu VW 7.2 no MacOS X (mas em outras versões
funciona):
- [50 timesRepeat: [Transcript
show: '/'. Processor yield]] fork.
[50 timesRepeat: [Transcript show: '\'. Processor yield]] fork.
- dou um chocolate para o aluno que descobrir o porquê.
- mas no squeak funcionou perfeitamente!
- 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 (só no VW).
- 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.
(note a nova forma de criar um
processo):
- p := Process
forContext: [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):
- p := Process
forContext: [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
- estes métodos devolvem o valor de variáveis de
classe com respectivos nomes e inicializados no método initialize da classe.
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 (uma fila
compartilhada contém um semáforo interno).
- 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 VisualWorks:
- |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 VisualWorks
- 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
Execução de Processos Externos no squeak
- Feito através da classe OSProcess e suas subclasses no
pacote OSProcess
- Possui suporte completo para vários tipos de UNIX e
Windows e incompleto para MacOS, OS/2 and RiscOS.
- Permite tanto criar processos externos quanto inspecionar em
tempo de execução os detalhes sobre eles.
- No Unix:
- processo :=
ExternalUnixOSProcess new.
processo programName:
'emacs';
pwd: '/usr/bin';
arguments: #('~/.emacs' '~/.acrorc');
forkChild.
- processo inspect.
Referências
- Daniel D. Abdala e Aldo v. Wangenheim. Conhecendo o Smalltalk.
Capítulo 10.
- (há alguns errinhos neste capítulo do livro)
Página de MAC 5714
Página do Fabio
Página do DCC