Vous êtes sur la page 1sur 9

1) (1) Descreva sucintamente a finalidade e funcionamento da funo fork(), referindo-se

ao significado
do valor de retorno desta funo.

2)
Pretende-se implementar, usando a API POSIX, um servidor que permita consultar pginas
de texto
remotamente. As pginas sero visualizadas partir do programa cliente que implementa as
seguintes
funcionalidades: a) Envio do nome do ficheiro a visualizar; b) Impresso no ecr do
contedo do ficheiro.
O cdigo do cliente o seguinte:
int main(int argc, char *argv[]) {
char buf[BUFSIZE];
int s, ssize;
struct sockaddr_in name;
struct hostent* hostinfo;
name.sin_family = AF_INET;
hostinfo = gethostbyname (argv[1]);
name.sin_addr = *((struct in_addr *) hostinfo->h_addr);
name.sin_port = htons (4000);
while(1) {
printf("Nome do ficheiro: "); fflush(stdout);
fgets(buf, BUFSIZE, stdin);
formata_string(buf, &ssize);
s = socket (PF_INET, SOCK_STREAM, 0);
connect(s, (struct sockaddr *) &name, sizeof (struct sockaddr_in));
write(s, buf, ssize);//envia-se nome, incluindo o '\0'
FILE *fps = fdopen(s,"r");
copy_stream(fps,stdout);
fclose(fps);
}
}
void copy_stream(FILE *src, FILE *dest) {
int ch;
while((ch=fgetc(src))!=EOF)
fputc(ch, dest);
}
void formata_string(char *buf, int *ssize){
*ssize=strlen(buf);
if(buf[*ssize-1]=='\n') //vamos eliminar o '\n', caso exista
buf[*ssize-1]='\0'; //'\n' substitudo pelo novo '\0'
else //caso no exista, aumentamos ssize, para contar o '\0' original

2c) (1.5) Altere o servidor de forma a que este possa atender vrios pedidos de cada vez
(servidor multitarefa).

3) (2.5) Explique o funcionamento e resuma a finalidade do extracto de cdigo


apresentado abaixo.
void sigchld_handler(int signum) {
wait(NULL);
}
int main() {
struct sigaction act;
act.sa_handler=sigchld_handler;
sigemptyset(&(act.sa_mask));
act.sa_flags=0;
sigaction(SIGCHLD, &act, NULL);
//(...)
}
4) (1.5) Explique o funcionamento e resuma a finalidade do extracto de cdigo
apresentado abaixo.
int main() {
int primeira_vez=1;
int pid;
while(1) {
begin_work();
if(primeira_vez)
primeira_vez=0;
else
waitpid(pid, NULL, 0);
pid = fork();
if(pid==0) {
finish_work();
exit(0);
}
}
}

5) (1.5) Considere o seguinte extracto de um programa:


int main(){
pid_t pid; int counter=5; int *p=&counter;
pid = fork();
if(pid==0) {
printf(%d\n, counter);
*p=1;
printf(%d\n, counter);
} else {
wait(NULL);
printf(%d\n,*p);
}
}
Explique qual ser a sucesso de valores impressos no ecr aps a execuo deste
programa.

6) (7.5%) Comente a utilizao da tcnica de polling em sistemas multi-tarefa.

7. a) (2.5%) Indique uma vantagem das aplicaes multi-processo (i.e., com utilizao da
funo fork) face s
aplicaes multi-thread.

8. (0.75) Assumindo que um processo configura o atendimento do sinal SIGCHLD, indique


em que situaes ele
poder receber esse sinal.

9. (3.5) Considere o seguinte extrato de um programa:


int i;
int main()
{
int j;
pid_t r;
i = 0;
for(j = 0; j < 4; ++j)
{
r = fork();
if(r == 0)
{
i = i + 1;
sleep(10);
printf("%d: %d\n", getpid(), i);
return 0;
}
}
printf("%d: %d\n", getpid(), i);
for(j = 0; j < 4; ++j)
wait(NULL);
printf("%d: %d\n", getpid(), i);
return 0;
}

10 (7.5) Considere o seguinte extrato de um programa:


int main()
{
int i = 10;

int fd = shm_open("/shm1", O_CREAT | O_RDWR, 0666);


ftruncate(fd, sizeof(int));
int *b = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
b[0] = 20;
sem_t *sem1 = sem_open("/sem1", O_CREAT | O_RDWR, 0666, 1);
sem_t *sem2 = sem_open("/sem2", O_CREAT | O_RDWR, 0666, 0);
pid_t r = fork();
if(r == 0)
{
sem_wait(sem2);
i = i - 1;
b[0] = b[0] - 1;
printf("%d: %d %d\n", getpid(), i, b[0]);
sem_post(sem1);
exit(0);
}
while(1)
{
sem_wait(sem1);
i = i - 1;
b[0] = b[0] - 1;
printf("%d: %d %d\n", getpid(), i, b[0]);
sem_post(sem2);
}
return 0;
}
Indique uma possvel sucesso de mensagens impressas no ecr aps a execuo deste
programa, assumindo que
no existe interferncia de outros processos no sistema. Justifique sucintamente, focandose nos pontos de
bloqueio de cada processo. Assuma que o identificador do processo inicial 2000 e que
o(s) novo(s) processo(s)
toma(m) o(s) valor(es) seguinte(s).
Nota: a sucesso de mensagens impressas dever ser apresentada de forma destacada e
isolada da justificao.

11. (3) Considere o seguinte extrato de um programa:


int i=0;
int main() {
sem_t *sem1 = sem_open("sem1", O_CREAT | O_RDWR, 0666, 0);
pid_t r = fork();
if(r == 0) {
sem_wait(sem1);
sleep(2);
printf("%d: %d\n", getpid(), i);
}
sleep(1);
i = i + 1;
sem_post(sem1);
printf("%d: %d\n", getpid(), i);

}
Indique uma possvel sucesso de mensagens impressas no ecr aps a execuo deste
programa,
assumindo que no existem interferncias de outros processos no sistema. Justifique
sucintamente.
Assuma que o identificador do processo inicial 2000 e que o(s) novo(s) processo(s)
toma(m) o(s)
valor(es) seguinte(s).

Resoluo

1) A funcao fork() permite que um programa possa criar um novo processo. O novo
processo tem uma
copia do codigo e dos dados do programa original e continua a execucao a partir da
funcao fork(). O
valor de retorno da funcao fork() e essencial neste processo pois permite que o
programa verifique se
ainda esta no processo original (neste caso o valor de retorno do fork() e um valor
maior do zero, o pid
do novo processo) ou no novo processo (neste caso o valor de retorno do fork() e
zero).

2c) Na resoluo da alnea a), substituir a linha abaixo


atende(ns);
por
pthread_t tid;
if(pthread_create(&tid, NULL, atende, ns)==0)
pthread_detach(tid);
else { //pode j ter atingido o nmero mximo de threads
perror(pthread);
atende(ns);
}

3) A finalidade do cdigo detectar a terminao de processos filhos e permitir que


eles terminem
completamente, evitando assim a existncia de processos zombie (assume-se portanto
que este programa
poder criar novos processos). Quando um processo termina, este envia o sinal SIGCHLD
ao processo
que o criou. O cdigo apresentado usa a funo sigaction para definir uma funo de
atendimento
(sigchld_handler) para esse sinal. A funo sigchld_handler por sua vez executa a
funo wait() que,
neste caso, faz com que o sistema liberte todos recursos ainda associados ao
processo. Ou seja, sempre
SISTC - Exame de Recurso (Parte A) 18/09/2009
LEEC - DEE - ISEP

que o processo receber o sinal de um dos processos filho (indicando assim a sua
terminao), a
funo sigchld_handler ser automaticamente executada, evitando assim que o processo
filho se torne
um zombie.

4) O ciclo comea por executar a funo begin_work(). Na primeira iterao do ciclo,


comea-se
simplesmente um novo processo que executar a funo finish_work() e termina
(exit(0)). Nos restantes

casos, o processo inicial ter que aguardar (atravs da funo waitpid()*) que o
processo filho criado no
ciclo anterior termine antes de poder criar o novo processo para execuo da funo
finish_work().
Desta forma, possvel ter a funo begin_work() de um novo ciclo a ser executado
concorrentemente
com a funo finish_work() do ciclo anterior.
*Nota: havia uma gralha no enunciado do exame, tendo aparecido wait em vez de
waitpid. No afecta a
resposta.

6)O problema do polling a possibilidade de gastar vrios ciclos de execuo do


processador sem fazer trabalho
til. Em sistemas multi-tarefa, esses ciclos poderiam ser usados para executar
outras tarefas. Dessa forma,
nestes sistemas, regra geral, o polling s dever ser usado quando o tempo
desperdiado inferior ao tempo de
comutao entre tarefas ou desprezvel na execuo geral do sistema.

7a) O facto de haver um erro que leve terminao de um dado processo no causa a
terminao de toda
aplicao. Isto pode ser especialmente til na implementao de servidores. No caso
das aplicaes multithread,
uma vez que todas as threads pertencem ao mesmo processo, um erro numa delas causa a
terminao do
processo e, por consequncia, de todas as threads.
8: Quando qualquer um dos seus processos filho muda de estado, i.e., quando terminam,
quando so parados
ou quando so continuados (isto , quando sai do estado parado). Nota:
possvel configurar a disposio
do sinal de forma a s receber o SIGCHLD devido a terminaes de processos filho

(SA_NOCLDSTOP).

10. A sequncia de impresses seria a seguinte:

2000: 9 19
2001: 9 18
2000: 8 17
Aps a criao do novo processo (fork()), o processo inicial entrar no ciclo while
(linha 25), ir decrementar o
valor do semforo sem1 (que se encontra a 1) e faz a primeira impresso. De seguida,
inicia uma nova iterao
do ciclo, encontrando sem1 a zero, o que o far aguardar na chamada funo
sem_wait (linha 27).
Entretanto, o novo processo, que se encontrava bloqueado na linha 16 (sem_wait com
sem2 a 0),
desbloqueado pela instruo da linha 31 (executada pelo processo inicial), atualiza
a sua cpia da varivel i

(de 20 para 19), decrementa o valor guardado na memria partilhada (linha 17), causa
a segunda impresso
apresentada acima, incrementa o valor do semforo sem1 e termina (linha 22). O
incremento de sem1
desbloqueia o processo inicial que, desta forma, executa uma nova iterao do ciclo
while, com a
correspondente impresso dos valores de i e de b, sendo que esta ltima varivel
reflete a alterao feita no
processo filho, uma vez que estava armazenada em memria partilhada por ambos os
processos.

11)
2000: 1
2001: 0
2001: 1
O novo processo fica bloqueado na funo sem_wait (valor inicial do semforo a 0) at que o processo
inicial faa o sem_post. A
pausa de 2 segundos d oportunidade ao processo inicial de executar primeiro o seu printf e terminar.
Passados cerca de 2
segundos, o processo filho executa o printf da linha 11, incrementa o valor de i (que havia sido herdado
a 0, valor na altura do
fork) na linha 15, faz o printf da linha 17 e termina.

Vous aimerez peut-être aussi