Última actualização: 1/12/2017, 9:00


Exercício 4

======================

Requisitos base

P: A matriz impressa no ficheiro de salvaguarda deve incluir também os
pontos das arestas?

R: Sim.

======================

P: Na secção "Experimente" do enunciado é dada uma sugestão de uma
execução para testar se o projeto está correto. Que valores dos
argumentos "maxD" e "iter" devem ser usados?

R: Devem ser escolhidos um valor "iter" grande o suficiente para que a
simulação termine devido ao maxD e não devido ao iter. Esta escolha
assegura que, tanto numa simulação contínua como simulação
interrompida e continuada (a partir de matriz salvaguardada), o número
de iterações total seja idêntico.

======================

P: O enunciado refere que, para o acesso a ficheiros, deverão ser usadas as funções fopen, fwrite, fread, fflush, fclose, etc. da biblioteca stdio.
Poderão ser usadas outras funções da stdio, tal como o fprintf?

R: Sim.

======================

P: Caso ocorra falha ao salvaguardar a matriz (e.g., impossibilidade de criar o processo filho ou erro no acesso ao ficheiro), como deve o projeto tratar essa falha?

R: Na presença de falhas relacionada com a salvaguarda, a salvaguarda deve ser cancelada de forma ordeira; no entanto, o processo do heatSim deve continuar normalmente.

======================

Requisitos avançados


P: Quando ocorre um SIGINT e existe um processo (lançado anteriormente) a salvaguardar a matriz, o que deve acontecer?

R: O enunciado é omisso quanto a esta situação, pelo que o grupo pode tomar a opção que achar mais conveniente.
Uma alternativa é o processo pai esperar pelo filho acabar de salvaguardar a matriz e logo depois o processo pai termina também.
Outra alternativa possível é o processo pai esperar pela terminação do filho e logo depois o processo pai iniciar novo processo de salvaguarda, antes de sair.
Ambas serão aceites como corretas.

======================


P: Nas teóricas foi discutido que o tratamento de signals usando a
função signal tem limitações conhecidas. Devemos mesmo assim usar esta
função?

R: Como ponto de partida, sim. No entanto, será valorizado o uso da
variante sigaction, que não sofre das limitações conhecidas da função
signal.

======================

P: Quando ocorre um signal que tem associado uma função de tratamento,
qual a tarefa (thread) que executa a função?

R: Em geral, o sistema operativo pode interromper qualquer uma das
tarefas do processo para nela executar a função. Isto traz um desafio:
caso a tarefa interrompida esteja na posse de um trinco (mutex) quando
é interrompida, será problemático se a função de tratamanto do signal
também tiver de adquirir o mesmo trinco -- facilmente ocorre uma
situação de interblocagem quando a função de tratamento tente fechar o
trinco.
Embora haja diferentes soluções para prevenir esta situação, a mais
simples passa por usar a função pthread_sigmask para forçar o sistema
operativo a usar sempre a tarefa mestre para tratar o signal.

======================

P: Quando ocorre um dos signals previstos no enunciado, o processo filho deve ser lançado imediatamente na função de tratamento do signal?

R: A função fork tem comportamento indefinido quando chamada de dentro de uma função de tratamento de signal, logo tal prática não deve ser seguida no projeto.
A melhor alternativa passa por separar os momentos em que o signal é tratado e em que o fork é chamado: (i) a função de tratamento do signal assinala (numa variável global) que ocorreu o signal; (i) o fork propriamente dito só é chamado quando a iteração em curso tiver terminado (a última tarefa trabalhadora a concluir a iteração consulta a variável global e cria o processo filho caso estejam reunidas as condições).

Exercício 3

======================
P: Qual deve ser o nome do executável e a ordem dos argumentos no Exercício 3?

R: O programa deve ser invocado da seguinte forma:
$ ./heatSim N tEsq tSup tDir tInf iter trab maxD
======================

P: A terminação dinâmica deve ser também implementada sobre a versão do heatSim com troca de mensagens?

R: Não. O exercício 3 foca-se exclusivamente na versão do heatSim com memória partilhada.

Exercício 1


======================
P: Para usar a mplib, cada tarefa deve ter associado um identificador inteiro. Como devem ser atribuídos?

R: Diferentes soluções são possíveis e aceites como corretas.  Por exemplo, atribuir os identificadores 0 até trab-1 às tarefas trabalhadoras (em que "trab" denota o número de tarefas trabalhadoras); e o inteiro seguinte à tarefa mestre. Ou, em alternativa, atribuir o identificador 0 à tarefa mestre e os identificadores 1, 2, etc às tarefas trabalhadoras.
Note-se que qualquer projecção entre as tarefas e os identificadores usados na mplib é válida desde que usada de forma coerente. Ou seja, nada impede que a quarta tarefa use o identificar 2. As sugestões acima pretendem apenas simplificar o código.

======================

P: Pode ser o mestre a alocar/preencher as fatias e depois passá-las como argumento no pthread_create? Pode a fatia final de uma tarefa ser devolvida por retorno da função da thread que terminou (no pthread_exit/return)?

R: Como o enunciado indica, "Após a criação das tarefas trabalhadoras, toda a comunicação e sincronização entre o mestre e as trabalhadoras deve ser realizada por troca de mensagens". Ou seja, deve ser cada tarefa trabalhadora a alocar as suas fatias privadas, devendo a tarefa mestre transmitir por mensagem (usando a mplib) enviada a cada trabalhadora o conteúdo da sua fatia inicial. De forma equivalente, o conteúdo final da fatia resultante de cada tarefa trabalhadora deve ser enviado por mensagem (via mplib) à tarefa mestre antes da tarefa trabalhadora terminar. Note-se que, usando pthreads, também seria possível implementar variantes em que as fatias são alocadas e preenchidas pela tarefa mestre e/ou em que a tarefa trabalhadora devolve um ponteiro para a sua matriz resultante. Estas variantes constituem híbridos entre troca de mensagens e partilha de memória, que estão fora do objetivo do exercício 1.
======================

P: Onde deve ser iniciada a blibioteca do mplib?

R: A mplib deve ser iniciada antes de se enviar ou receber qualquer mensagem e apenas deve ser inciada uma vez. Sugere-se que isto seja feito no main antes de criar qualquer filho e antes de enviar/receber qualquer mensagem.

======================

P: Quando verificamos que foi retornado erro na chamada a uma  função (por exemplo, na reserva de memoria), o que é que é mais apropriado fazer? 

R: Por vezes, existe um plano B que é possível seguir quando o plano A falha. No caso do projecto, é raro isto acontecer. Sugerimos que simplesmente abortem a execução fazendo “exit”. Para reportar uma mensagem de erro, usem o "perror" quando o erro ocorrer numa chamada ao sistema ou fprintf para o stderr noutros casos,  por exemplo "fprintf( stderr, “a funcao xpto retornou o erro %d. Abortando...\n”, ret);"

======================
P: Cada escravo deve manter uma cópia de toda a matriz ou só de parte da matriz?

R: Uma vez que não há partilha de memória no projecto 1, cada fio de execução escravo necessita de ter as suas estruturas de dados privadas, em que só ele pode escrever. Uma vez que cada escravo só lê e só escreve na sua fatia (lendo também as linha adjacentes), é um grande desperdício de memória se todos os escravos reservarem espaço para uma matriz inteira. Assim, é melhor que cada escravo crie matrizes mais pequenas, apenas para o que necessita, ou seja, suficientes para alojar a sua fatia mais as linhas adjacentes.
======================
P: A capacidade dos canais é relevante?

R: É possível encontrar uma solução para este problema que funciona qualquer que seja a capacidade do canal (inclusive em modo "rendez-vous", isto é, com capacidade 0). Sugere-se que os alunos primeiro encontrem uma solução que funcione para canais com uma capacidade à escolha (>0), e depois experimentem essa solução com canais de menor capacidade até chegar a 0.