# Resposta da prova de concorrente
Ideia do enunciado da prova, não lembro exatamente o que era pra fazer: Implementar duas funções `exec_load` e `exec`. A função `exec_load` recebe uma lista de requisições e cada requisiçao tem uma requisição "pai", apenas uma, menos a requisição 0, que não tem pai.
A função exec implementa a chamada a uma função que fará a requisição, porém se a requisiçao demorar mais que 5 segundos ele tem q dar timeout e se a requisição der timeout ela tem que retornar -1, caso contrário deve retornar 0.
Além disso, a função `exec_load` recebe um parametro que é o *max_workers*, sendo esse o número máximo de requisições que podem estar executando ao mesmo tempo.
Por fim, a principal restrição do problema é: Uma requisição só pode ser executada depois que os seus antepaçados são executados.
## ìndice
- [Tipo Request](#tipo-request)
- [Definindo o tipo Node](#Definindo-tipo-novo)
- [Executando de fato a requisicao](#Executando-de-fato-a-requisicao)
- [Relacionando o node a execucao](#Relacionando-o-node-a-execucao)
- [A função exec_load](#A-funcao-exec_load)
- [Código completo](#Codigo-completo)
## Tipo request
```go=
type request struct {
req_id int
antpassado_id int
succs []int
}
```
Tipo request que foi dado na questão para manipularmos
## Definindo tipo novo
```go=
type node struct {
req_id int
succs []Node // Os filhos do nó atual
}
```
Tipo nó que possui os atributos:
- `req_id` *(int)*: Id da requisição que esse nó deve fazer;
- `succs` *(Node list)*: Lista de filhos (do tipo *Node* também) que esse nó possui;
## Executando de fato a requisicao
A função a seguir serve para fazer de fato a requisição, essa é uma função que foi exigida que nós implementassemos.
```go=
func exec(r request) int {
ticker := time.Ticker(5 * time.Second)
reqChan := make(chan int, 1)
go do_exec(r, reqchan)
select {
case <- ticker:
return -1
case <- reqChan:
return 0
}
}
```
Na função acima temos:
- **ticker**: Em Go o `time.ticker` retorna um canal que a cada 5 segundos, nesse caso, adiciona no canal um valor aleatorio padrao do tipo, 0 nesse caso, acho);
- **do_exec**: Função abstraída que vai servir para fazer de fato a requisição, ela recebe o objeto requisição passado como parâmetro da função e o canal cujo o valor de retorno da requisição vai ser adicionado;
- **reqChan**: Canal que vai servir para colocarmos o resultado da requisição.
Agora vamos para o **select**. O select serve pra a gente dizer pra os canais que estao nas clausulas `case` assim: "Olhe vcs dois, quero o conteúdo que tem no canal de vcs, mas vou pegar o primeiro que chegar!", dessa forma, se a requisição demorar mais do que 5 segundos a função retorna -1, caso contrário retona 0.
## Relacionando o node a execucao
```go=
func execReq(node Node, bufferReq chan int) {
req := request(node.req_id)
bufferReq <- req_id
result := exec(req)
<- bufferReq
for soc in node.soccs {
execReq(soc, bufferReq)
}
}
```
Na função acima temos:
- **request()**: Função que não precisa implementar que recebe o id da requisição do nó e retorna a requisição de fato;
- **bufferReq**: Canal que servirá para limitarmos a quantidade máxima de requisições que são executadas de forma paralela;
As linhas 3-5 da função acima tem como objetivo evitar que um número de requisições que seja maior do que o tamanho do buffer sejam executadas ao mesmo tempo, dessa forma, antes de executar a função [exec](#Executando-de-fato-a-requisicao) é adicionado no buffer um número arbitrario e depois de executada a função é retirado um valor do buffer, dando lugar a outra gouroutine qu esteja bloqueada esperando uma vaga para executar sua requisição.
Nas linahs 7 e 8 cada filho do nó atual roda a função `execReq`, sendo essa uma função recursiva que vai ser retornada quando o chegarmos nos nós folha.
## A funcao exec_load
```go=
func exec_load(workload []request, max_workers int) {
bufferRequest := make(chan int, max_workers)
rootNode := createTree(workload)
execReq(rootNode, bufferRequest)
}
```
Na função acima temos:
- **bufferRequest** *(chan int)*: Canal buffer que servirá para controlar a quantidade de requisições que podem ser feitas de forma paralela;
- **createTree** *(func)*: Função arbitraria que não precisou ser implementada, mas que transforma a lista de requests em uma árvore e retorna o nó raiz.
Essa função precisava ser implementada e é a que inicia todo o processo de chamadas das requisições, a partir do nó raiz.
## Codigo completo
```go=
type node struct {
req_id int
succs []Node // Os filhos do nó atual
}
func exec(r request) int {
ticker := time.Ticker(5 * time.Second)
reqChan := make(chan int, 1)
go do_exec(r, reqchan)
select {
case <- ticker:
return -1
case <- reqChan:
return 0
}
}
func execReq(node Node, bufferReq chan int) {
req := request(node.req_id)
bufferReq <- req_id
result := exec(req)
<- bufferReq
for soc in node.soccs {
execReq(soc, bufferReq)
}
}
func exec_load(workload []request, max_workers int) {
bufferRequest := make(chan int, max_workers)
rootNode := createTree(workload)
execReq(rootNode, bufferRequest)
}
```