Exercício III: Manipulação de Processos

Esta aula tem por objectivo familiarizá-lo com as operações básicas de manipulação de processos em ambientes UNIX: criação, terminação, relação com outros processos, pipes e sinais. Para tal, deverá implementar pequenos programas que respondam aos requisitos de cada uma das tarefas que se seguem. Para obter mais informação sobre as funções de sistema referidas, consulte as man-pages respectivas.
  1. Criar um novo processo: o programa deve criar um processo filho e ambos os processos (pai e filho) devem imprimir o seu PID, PPID e UID. Funções a ter em conta: fork, getpid, getppid e getuid.
  2. Criar uma descendência directa de N processos: o programa deve criar N processos filho do processo original. Cada processo filho deve escrever o seu PID e o PID do processo pai.
  3. Criar uma série de N processos: o programa deve criar uma série de N processos, em que cada processo p cria o processo p+1. Por exemplo, para N=4, o 1º processo da série cria o 2º, o 2º cria o 3º e o 3º cria o 4º. Cada processo deve escrever o seu PID e o PID do processo pai.
  4. Sincronizar processos: o programa deve criar um processo filho que calcula o número de Fibonacci de ordem 10 e que termina enviando esse cálculo como sinal ao processo pai. O processo pai deve esperar que o processo filho termine, apanhar o sinal enviado e escreve-lo. Funções a ter em conta: exit e wait.
  5. Criar um processo para executar um dado comando: o programa deve criar um processo filho para executar o comando ls -l. Funções a ter em conta: família de funções exec.
  6. Enviar mensagens através de uma pipe: o programa deve criar um processo filho e enviar-lhe duas mensagens, "Hello world!" e "Goodbye!", terminando em seguida. Por sua vez, o processo filho deverá imprimir para o ecrã as mensagens à medida que as for recebendo, terminando assim que o processo pai feche a ligação. Não se esqueça de, em cada um dos processos, fechar os descritores que não vão ser usados. Funções a ter em conta: pipe, write, read e close.
  7. Saída paginada: o programa deve criar um processo filho para paginar no ecrã as mensagens do processo pai. O processo pai deve enviar ao processo filho a seguinte sequência de linhas:
          Linha 1 
          Linha 2 
          ...
          Linha 100
    O processo filho deve executar o programa more para paginar no ecrã a sequência de linhas recebida do processo pai. Como o paginador more precisa de ter acesso exclusivo ao terminal, o processo pai não deve terminar antes do processo filho. Funções a ter em conta: dup2.
  8. Apanhar sinais: o programa deve definir um handler para apanhar os sinais SIGTSTP (enviado pelo terminal quando se usa CTRL-Z) e SIGINT (enviado pelo terminal quando se usa CTRL-C), imprimindo nesses casos uma mensagem adequada. O programa deve começar por imprimir o seu PID, instalar de seguida o handler, e finalmente entrar num ciclo infinito até receber o sinal SIGKILL. Para enviar o sinal SIGKILL ao processo deverá invocar numa outra shell o comando kill -9 para o PID que o programa imprimiu. Funções a ter em conta: signal e pause.
  9. Sincronização por sinais: o programa deve criar um processo filho e ambos os processos (pai e filho) devem imprimir alternadamente linhas, de modo a obter uma sequência semelhante à seguinte:
          Filho: 1 
          Pai: 2 
          Filho: 3 
          ...  
          Pai: 18
          Filho: 19
          Pai: 20
    O processo filho deve imprimir as linhas ímpares e o processo pai as linhas pares, até atingirem um determinado valor (20 no exemplo). Para indicar ao outro a sua vez de imprimir, os processos devem trocar sinais do tipo SIGUSR1. Funções a ter em conta: kill.