detalhes finais do relatorio
[3hU9fRjo95.git] / relatorio / relatorio.tex~
blob95b906bf051734764d41f5f99c1db57939cc68d9
1 \documentclass[a4paper,10pt]{abnt} %
2 \usepackage[utf8]{inputenc}
3 \usepackage[T1]{fontenc}
4 \usepackage[brazil]{babel}
5 \usepackage{listings}
6 \usepackage{color}
8 %opening
9 %\title{}
10 %\author{Kauê Silveira \\171671 \and Silveira Kauê \\ 671171}
12 \autor{Kaue Soares da Silveira \\ 171671} %\and
13 \instituicao{Universidade Federal do Rio Grande do Sul}
14 \orientador[Professor:]{Alexandre Carissimi}
15 \titulo{Trabalho Opcional 1: Estudo da Linguagem Golang}
16 \comentario{Disciplina INF01151 - Sistemas Operacionais II N}
17 \data{}
19 \definecolor{gray}{rgb}{0.5, 0.5, 0.5}
20 \definecolor{darkBlue}{rgb}{0.15,0.18,0.40}
21 \definecolor{darkGreen}{rgb}{0.15,0.40,0.18}
22 \lstset{extendedchars=true,
23         inputencoding=utf8,
24         basicstyle=\small\color{blue},
25         keywordstyle=\color{red}\bfseries,
26         keywordstyle= [2]\color{magenta}\bfseries,
27         identifierstyle=\color{blue},
28         commentstyle=\color{gray}\textit,
29         stringstyle=\color{darkGreen},
30         showstringspaces=false,
31         tabsize=2
34 \lstset{
35         numbers=left,         % Números na margem da esquerda
36         numberstyle=\tiny\color{darkGreen},    % Números pequenos
37         stepnumber=1,         % De 1 em 1
38         numbersep=5pt         % Separados por 5pt
40 \lstdefinelanguage{Go}{%
41       morekeywords=[1]{func, int, chan, package, import, int64, var, const, type, struct, byte},% blocks
42       morekeywords=[2]{make, go, select, for, case, if, then, else, len, cap, break},%
43       morekeywords=[3]{idvar,var,->,as},% variables
44       morekeywords=[4]{lexical,sum,join},% aggregation/sorting
45       morekeywords=[5]{},% regexps (s.moredelim below)
46       morestring=[b]",%
47       morecomment=[l]{\#},%
48       morecomment=[l]{//},%
49       morecomment=[s]{\\\#}{\#\\\\)},%
50       morecomment=[s]{/*}{*/},%
51       alsodigit={-},%
52       literate= {->}{$\rightarrow$}{2},%
53       sensitive%
54     }[keywords,strings]
56 \lstdefinelanguage{Shell}{%
57       morekeywords=[1]{sudo, apt-get, install, cd, export, hg, mkdir, mv, gedit, easy_install, clone, release, g, l, make},% blocks
58       morekeywords=[2]{declare,some,position,pos,optional,opt,where,order-by,group-by,and,or,not},%
59       morekeywords=[2]{variable,ns-default,ns-prefix,not,if,then,else,case,without,desc,descendant,in,identity},%
60       morekeywords=[3]{idvar,var,->,as},% variables
61       morekeywords=[4]{lexical,sum,count,join},% aggregation/sorting
62       morekeywords=[5]{},% regexps (s.moredelim below)
63       morestring=[b]",%
64       morecomment=[l]{\#},%
65       morecomment=[s]{\\\#}{\#\\\\)},%
66       alsodigit={-},%
67       literate= {->}{$\rightarrow$}{2},%
68       sensitive%
69     }[keywords,strings]
71 \begin{document}
73 %\maketitle
74 \folhaderosto
75 \sumario
77 %\begin{abstract}
78 %\begin{resumo}
79 %\end{abstract}
80 %\end{resumo}
82 \chapter{Introdução}
83         \begin{quotation}
84 \emph{"Não comunique-se compartilhando memória, compartilhe
85 memória comunicando-se."}
86         \end{quotation}
88  O simples ato de comunicação garante a sincronização.
90         Concorrência em muitos ambientes se torna difícil pelas sutilezas envolvidas
91 no acesso correto a variáveis compartilhadas. Go\cite{GO} encoraja uma abordagem
92 diferente, na qual variáveis compartilhadas são passadas através de canais e
93 nunca são de fato ativamente compartilhadas por threads de execução separadas.
94 Apenas uma gorotina tem acesso à variável num dado momento de tempo. Condições
95 de corrida relativas aos dados não podem ocorrer, por construção. Modelo de concorrência inspirado no CSP \cite{CSP}.
96 \chapter{Primeiros Passos}
97         \section{Instalação}
98         Passos que eu segui no Ubuntu 9.10:
100 \begin{lstlisting}[language=Shell, texcl=true, numbers=none, escapechar={\%}]
101 $ cd ~
102 $ gedit .bashrc &
103 # colar no final:
104         export GOROOT=$HOME/go
105         export GOARCH=386
106         export GOOS=linux
107 # reiniciar o shell para que as alterações tenham efeito
108 $ sudo apt-get install bison gcc libc6-dev ed gawk %make%
109 $ sudo apt-get install python-setuptools python-dev build-essential gcc
110 $ sudo easy_install mercurial
111 $ hg clone -r release https://go.googlecode.com/%hg%/ $GOROOT
112 $ cd $GOROOT/src
113 $ mkdir $HOME/bin
114 $ ./all.bash
115 $ cd $HOME/bin
116 $ sudo mv * /bin
117 \end{lstlisting}
119 \section{Utilização}
120 \begin{lstlisting}[language=Shell, texcl=true, numbers=none, escapechar={\%}]
121 # criar o arquivo fonte num editor de sua preferência
122 $ gedit prog.go & # -> prog.go
123 # compilar
124 $ %\color{red}{8}%g prog.go # -> prog.8
125 # ligar
126 $ %\color{red}{8}%l -o prog prog.8 # -> prog
127 # executar
128 $ ./prog
129 \end{lstlisting}
131 \chapter{Mecanismos de Programação Concorrente}
132         \section{Gorotinas}
133                 Go tem seu próprio modelo de processo / thread / corotina,
134 chamado gorotina (\emph{goroutines}). Gorotinas são divididas de acordo com o necessário em threads (de usuário) e processos do sistema. Quando uma goroutine executa uma chamada de sistema bloqueane, nenhuma outra gorotina é bloqueada. Para configurar o número máximo de processos criados podemos modificar a variável de ambiente \lstinline|\$GOMAXPROCS| ou utilizar a função runtime.GOMAXPROCS (n int) durante a execução. Seu valor default é 1, ou seja, todas as gorotinas são threads de usuário pertencentes ao mesmo processo.
136         \section{Channel}
137                 Representa um canal de comunicação / sincronização que pode conectar duas
138 computações concorrentes. Na realidade são referências para um objeto que
139 coordena a comunicação.
141                 <- é o operador binário de comunicação (envio) <- também é o operador, desta vez unário, de recebimento. Ambos são atômicos.
143                 Operações de leitura (respesctivamente, escrita) em canais que não têm buffer ou que estão com o buffer vazio (respectivamente, cheio) bloqueiam, e o bloqueio se mantém até que haja aconteça uma operação de escrita (respectivamente, leitura). A linguagem também permite leitura (respectivamente, escrita) não bloqueante, a qual retorna imediatamente uma flag dizendo se a operação foi realizada com sucesso ou não.
145                 Na criação são sempre bidirecionais, mas quando são recebidos como parâmetro por uma função, além da declaração normal (chan T) podem ser declarados para apenas receber (<-chan T) e apenas enviar (chan<- T), com o objetivo garantir que serão utilizados corretamente no corpo da função.
147                 As funções len e cap, quando aplicadas a canal, retornam, repspectivamente, a quantidade de mensagens esperando e o tamanho do buffer do canal (caso este seja assíncrono), ou zero caso contrário. São úteis para determinar se o buffer de um canal assíncrono está cheio, o que permite evitar torná-lo síncrono.
149                 Exemplos:
151 \begin{lstlisting}[language=Go, texcl=true, escapechar={\%}]
152 // declaração:
153         var canal_sincrono chan int // envia e recebe inteiros
154         var canal_assincrono chan int // poderia ser qualquer outro tipo
155 // instanciação:
156         canal_sincrono = make (chan int) 
157         canal_assincrono = make (chan int, 10) // buffer de tamanho 10
158 // função que utiliza um canal apenas para leitura
159         func so_leio (canal_leitura <-chan int) { ... }
160 // função que utiliza um canal apenas para escrita
161         func so_escrevo (canal_escrita chan<- int) { ... }
162 // função que utiliza um canal bidirecional
163         func leio_e_escrevo (canal chan int) { ... }
164 // tipos de leitura:
165         v := <-canal_sincrono // sempre leitura sincrona
166         v := <-canal_assincrono // leitura assincrona quando houver espaço no buffer, síncrona caso contrário
167         v, ok := <-canal // sempre leitura assíncrona, ok é setado para true ou false de acordo com o sucesso
168 // tipos de escrita:
169         canal_sincrono <- v // sempre escrita síncrona
170         canal_assincrono <- v // escrita assíncrona quando houver espaço no buffer, síncrona caso contrário
171         ok := canal <- v // sempre escrita assíncrona, ok é setado para true ou false de acordo com o sucesso
172 // axiomas:
173         // 0 <= len(canal) <= cap(canal), para qualquer canal
174         // cap(make(chan int)) = 0
175         // cap(make(chan int, n)) = n
176 \end{lstlisting}
178         \section{go}
179                 É o operador que inicia a execução concorrente de uma gorotina, sempre no mesmo espaço de endereçamento. Prefixe uma chamada de função ou de método com a palavra-chave go para executar a chamada numa nova gorotina. Quando a chamada termina, a gorotina também termina (silenciosamente). O efeito é similar a notação \& do shell Unix para rodar um comando em background.
181                 Exemplo:
183 \begin{lstlisting}[language=Go, texcl=true, escapechar={\%}]
185 func faz_algo () { ... }
187 func main () {
188         ...
189         // inicia a execução concorrente da função faz\_algo ...
190         go faz_algo ()
191         // ... e continua executando ...
192         ...
194 \end{lstlisting}
196         \section{select}
197                 É um estrutura de controle análoga a um switch, mas que age sempre sobre comunicações. Escolhe qual das comunicações listadas em seus casos pode prosseguir. Se todas estão bloqueadas, ele espera até que alguma desbloqueie. Se várias podem prosseguir, ele escolhe uma aleatoriamente.
199                 Exemplo:
201 \begin{lstlisting}[language=Go, texcl=true, escapechar={\%}]
202 // esta função envia zeros e uns aleatoriamente a cada iteração
203 func gerador_aleatorio_de_bits (canal chan<- int)
204         for { // laço infinito
205                 select { // escolha não-determinística
206                         case c <- 0: // nada no corpo do case, o break é implícito (diferente de c)
207                         case c <- 1:
208                 }
209         }
210 \end{lstlisting}
212 \chapter{Prática}
213         \section{Compilando e executando os exemplos}
215                 Todos os exemplos, exceto o hello.go, implementam a solução do problema produtor-consumidor com buffer limitado e taxa de produção e consumo aleatórias, sendo que o pc\_channel\_multi.go implementa a versão com vários produtores e vários consumidores. Os outros implementam a versão singular apenas para manter a simplicidade, mas também são facilmente generalizáveis.
217 \begin{lstlisting}[language=Shell, texcl=true, numbers=none, escapechar={\%}]
218 $ cd src
219 $ make
220 $ ./programa_desejado
221 \end{lstlisting}
222         \section{Hello, World!}
223                 \begin{description}
224                         \item[Arquivo:] hello.go
225                 \end{description}
226 \lstinputlisting[language=Go, texcl=true, escapechar={\#}]{../hello.go}
228         \section{Funções Auxiliares}
229 \lstinputlisting[firstline=11, lastline=17, language=Go, texcl=true, numbers=none, escapechar={\$}]{../pc_channel.go}
230 \lstinputlisting[firstline=18, lastline=22, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_channel.go}
231 \lstinputlisting[firstline=23, lastline=27, language=Go, texcl=true, numbers=none, escapechar={\$}]{../pc_channel.go}
232 \lstinputlisting[firstline=28, lastline=32, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_channel.go}
233 \lstinputlisting[firstline=33, lastline=40, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_channel.go}
234 \lstinputlisting[firstline=42, lastline=45, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_channel.go}
235 \lstinputlisting[firstline=47, lastline=51, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_monitor_cond.go}
236 \lstinputlisting[firstline=32, lastline=46, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_monitor_cond.go}
237 %\lstinputlisting[firstline=, lastline=, language=Go, texcl=true, escapechar={\#}]{../pc_channel.go}
239         \section{Constantes}
240 \lstinputlisting[firstline=32, lastline=36, language=Go, texcl=true, numbers=none, escapechar={\#}]{../pc_mutex.go}
242         \section{Destruição (de variáveis)}
243                 Como a linguagem tem coletor de lixo, não é necessário (nem possível) se preocupar com a destruição das variáveis.
245         \section{Mutex}
246                 \begin{description}
247                         \item[Criação]:
248 \begin{lstlisting}[language=Go, numbers=none]
249 import . "sync"
250 var mutex *Mutex = new(Mutex)
251 \end{lstlisting}
252                         \item[Uso]:
253 \begin{lstlisting}[language=Go, texcl, numbers=none]
254 mutex.Lock()
255         // seção crítica
256 mutex.Unlock()
257 \end{lstlisting}
258                         \item[Arquivo:] pc\_mutex.go
259                         \item[Implementação (parte principal)]:
260 \lstinputlisting[firstline=37, lastline=91, language=Go, texcl=true, escapechar={\#}]{../pc_mutex.go}
261                 \end{description}
263         \section{Semáforo}
264                 \begin{description}
265                         \item[Criação]:
266 \begin{lstlisting}[language=Go, texcl, numbers=none]
267 var semaforo chan int = make(chan int, MAX_VAL) // o semáforo sempre começa em 0
268 \end{lstlisting}
269                         \item[Inicialização]:
270 \begin{lstlisting}[language=Go, texcl, numbers=none]
271 // atribui o valor inicial n para o semáforo
272 // com n = 1 simulamos um mutex
273 for i := 0; i < n; i++ {
274         signal(semaforo)
276 \end{lstlisting}
277                         \item[Uso]:
278 \begin{lstlisting}[language=Go, texcl, numbers=none]
279 wait(semaforo)
280         // seção crítica
281 signal(semaforo)
282 \end{lstlisting}
283                         \item[Arquivo:] pc\_sem.go
284                         \item[Implementação (parte principal)]:
285 \lstinputlisting[firstline=36, lastline=110, language=Go, texcl=true, escapechar={\#}]{../pc_sem.go}
286                 \end{description}
288         \section{Monitor}
289                 \begin{description}
290                         \item[Criação]:
291 \begin{lstlisting}[language=Go, texcl, numbers=none]
292 type Monitor struct {
293         mutex *Mutex
294         // outros campos ...
296 \end{lstlisting}
297                         \item[Inicialização]:
298 \begin{lstlisting}[language=Go, texcl, numbers=none]
299 func newMonitor () *Monitor {
300         return &Monitor {
301                 new(Mutex),
302                 // inicializar outros campos ...
303         }
305 var monitor *Monitor = newMonitor()
306 \end{lstlisting}
307                         \item[Uso]:
308 \begin{lstlisting}[language=Go, texcl, numbers=none]
309 func (m *Monitor) metodo () {
310         m.mutex.Lock()
311                 // fazer o que tem que fazer ...
312         m.mutex.Unlock()
314 monitor.metodo()
315 \end{lstlisting}
316                         \item[Arquivo:] pc\_monitor.go
317                         \item[Implementação (parte principal)]:
318 \lstinputlisting[firstline=37, lastline=110, language=Go, texcl=true, escapechar={\#}]{../pc_monitor.go}
319                         \item[Discussão]: semáforos são utilizados para simular as variáveis de condição. As diferenças entre ambos são:
320                                 \begin{description}
321                                         \item[Memória:] semáforos têm memória, no sentido de que sinalização nunca são perdidas, pois permanecem armazenadas no semáforo. Variáveis de condição não tem memória, caso não haja ninguém esperando quando ocorre um sinal, o sinal se perde.
322                                         \item[Atomicidade:] variáveis de condição destravam o mutex e entram em estado de espera de forma atômica. Isso é necessário pois, se houvesse uma troca de contexto entre estas duas ações, um outra thread poderia entrar no monitor e gerar um sinal que seria perdido, podendo causar um deadlock. Os semáforos, ao contrário, não realizam estas duas operações de forma atômica, mas isso não é um problema, já que os sinais não se perdem.
323                                 \end{description}
324                 \end{description}
326         \section{Variável de Condição}
327                 \begin{description}
328                         \item[Criação]:
329 \begin{lstlisting}[language=Go, texcl, numbers=none]
330 // canal sem buffer
331 var cond chan int = make(chan int)
332 \end{lstlisting}
333                         \item[Uso]:
334 \begin{lstlisting}[language=Go, texcl, numbers=none]
335 wait_cond(cond, mutex)
336 trysignal(cond)
337 \end{lstlisting}
338                         \item[Arquivo:] pc\_monitor\_cond.go
339                         \item[Implementação (parte principal)]:
340 \lstinputlisting[firstline=57, lastline=130, language=Go, texcl=true, escapechar={\#}]{../pc_monitor_cond.go}
341                         \item[Discussão]: a semântica das variáveis de condição diz que o destrancamento do mutex tem que acontecer de forma atômica com o início da espera pela variável (ver discussão na seção sobre Monitor). A melhor tentativa de simular esta atomicidade foi criar uma outra gorotina (waiter) e deixá-la esperando pelo variável de condição antes de destrancar o mutex, e então esperar pela resposta desta gorotina. Porém, mesmo esta implementação está incorreta, pois não há como garantir que a gorotina criada já esteja esperando pela variável de condição antes de destrancarmos o mutex. Portanto, não há como implementar variáveis de condição corretamente na linguagem, podemos apenas simular seu comportamente com semáforos, mas são coisas diferentes. Para se ter uma idéia da chance de ocorrência do deadlock, no meu computador pessoal o programa acima entrou em deadlock em média após 40000 iterações.
342                 \end{description}
344         \section{The Go Way}
345                 Os canais de go são exatamente o que precisamos para comunicação entre as gorotinas. Veja como a solução é bem mais elegante:
346                 \begin{description}
347                         \item[Arquivo]: pc\_channel.go
348                         \item[Implementação (parte principal)]:
349 \lstinputlisting[firstline=52, lastline=130, language=Go, texcl=true, escapechar={\#}]{../pc_channel.go}
350                 \end{description}
352         \section{Múltiplos Produtores e Consumidores}
353                 \begin{description}
354                         \item[Arquivo]: pc\_channel\_multi.go
355                         \item[Execução]:
356 \begin{lstlisting}[language=Shell, texcl=true, numbers=none, breaklines, escapechar={\%}]
357 $ ./pc_channel_multi.go -s BUFFER_SIZE -t MAX_SLEEP_TIME -m MAX_PRODUCTIONS -p N_PRODUCERS -c N_CONSUMERS
358 \end{lstlisting}
359                         \item[Implementação (parte principal)]:
360 \lstinputlisting[firstline=40, lastline=130, language=Go, texcl=true, escapechar={\#}]{../pc_channel_multi.go}
361                 \end{description}
363 \chapter{Conclusão}
364         Go é uma linguagem que tenta aliar um certo nível de abstração (coletor de lixo, canais inspirados num modelo formal amplamente aceito) com eficiência de compilação e execução. A linguagem não apresenta nativamente algumas funcionalidades comuns de concorrência, mas sua implementação é relativamente fácil, pois a linguagem possui o tipo canal que é tão poderoso quanto as funcionalidades a que estamos acostumados.
366         Com a disseminação de computadores multiprocessados, e as dificuldades que temos atualmente para programar corretamente sistemas concorrentes, certamente linguagens como essa terão grande crescimento e importância, podendo começar a substituir gradualmente linguagens mais antigas (como C), pois a ineficiência de execução de suas abstrações individualmente vai ser compensada pela eficiência de sua execução como um todo, por aproveitarem melhor os recursos de hardware disponíveis.
368 \begin{thebibliography}{10}
369         \bibitem{GO} \emph{The Go Programming Language}, http://golang.org/. Acessado em: 04/04/2010.
370         \bibitem{CSP} Hoare, C. A. R., \emph{Communicating Sequential Processes},  Communications of the ACM 21 (8): 666–677.
371 \end{thebibliography}
373 \end{document}