Mudanças entre as edições de "SOP29005-2020-1"
(47 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 552: | Linha 552: | ||
* Slides do Capítulo 4 do livro do Silberschatz | * Slides do Capítulo 4 do livro do Silberschatz | ||
− | =AULA 10 ?? - REMOTA - Dia | + | =AULA 10 ?? - REMOTA - Dia 24/03/2020= |
− | |||
==Objetivos/Conteúdos== | ==Objetivos/Conteúdos== | ||
− | *Webconf | + | * Webconf |
− | *Revisão de Threads | + | * Revisão de Threads |
− | *Laboratório de Thread de Applicação | + | * Laboratório de Thread de Applicação |
==Slides para esta aula== | ==Slides para esta aula== | ||
Linha 568: | Linha 567: | ||
{{collapse top| bg=lightyellow | expandir=true | Threads de aplicação}} | {{collapse top| bg=lightyellow | expandir=true | Threads de aplicação}} | ||
− | == Threads de aplicação == | + | ==Threads de aplicação== |
− | |||
O Linux, através da API POSIX, oferece um conjunto de funções que permite às aplicações manipular contextos, facilitando a vida do programador que quer implementar tarefas "simultâneas" dentro de um único processo, ou seja, threads. As seguintes funções e tipos estão disponíveis: | O Linux, através da API POSIX, oferece um conjunto de funções que permite às aplicações manipular contextos, facilitando a vida do programador que quer implementar tarefas "simultâneas" dentro de um único processo, ou seja, threads. As seguintes funções e tipos estão disponíveis: | ||
− | *'''getcontext(&a)''': salva o contexto na variável '''a'''; | + | * '''getcontext(&a)''': salva o contexto na variável '''a'''; |
− | *'''setcontext(&a)''': restaura um contexto salvo anteriormente na variável '''a'''; | + | * '''setcontext(&a)''': restaura um contexto salvo anteriormente na variável '''a'''; |
− | *'''swapcontext(&a,&b)''': salva o contexto atual na variável '''a''' e restaura o contexto salvo anteriormente na variável '''b'''; | + | * '''swapcontext(&a,&b)''': salva o contexto atual na variável '''a''' e restaura o contexto salvo anteriormente na variável '''b'''; |
− | *'''makecontext(&a, ...)''': ajusta parâmetros internos do contexto salvo em '''a'''; | + | * '''makecontext(&a, ...)''': ajusta parâmetros internos do contexto salvo em '''a'''; |
− | *'''ucontext_t''': as variáveis '''a''' e '''b''' são do tipo '''ucontext_t'''. Este tipo armazena um contexto. | + | * '''ucontext_t''': as variáveis '''a''' e '''b''' são do tipo '''ucontext_t'''. Este tipo armazena um contexto. |
Busque mais informações sobre estas funções utilizando o programa manpage do Linux (ex.: man getcontext). | Busque mais informações sobre estas funções utilizando o programa manpage do Linux (ex.: man getcontext). | ||
Linha 664: | Linha 662: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | *Exercício 1: Primeiramente compile e execute o código. Agora estude o código e entenda completamente o seu funcionamento. Explique em DETALHES o código, comentando todas as linhas. Na seção de diagrama do seu relatório, desenhe um diagrama de funcionamento do código para mostrar exatamente como acontece a troca de contexto entre as threads. | + | * Exercício 1: Primeiramente compile e execute o código. Agora estude o código e entenda completamente o seu funcionamento. Explique em DETALHES o código, comentando todas as linhas. Na seção de diagrama do seu relatório, desenhe um diagrama de funcionamento do código para mostrar exatamente como acontece a troca de contexto entre as threads. |
− | *Exercício 2: Acrescente um procedimento '''f_new''' que receba 4 strings como parâmetros e imprima todas na tela. Antes do final da execução do main faça uma mudança de contexto para chamar o procedimento criado. | + | * Exercício 2: Acrescente um procedimento '''f_new''' que receba 4 strings como parâmetros e imprima todas na tela. Antes do final da execução do main faça uma mudança de contexto para chamar o procedimento criado. |
− | <!-- | + | <!--<syntaxhighlight lang=c> |
− | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
Linha 775: | Linha 772: | ||
exit(0); | exit(0); | ||
} | } | ||
− | </syntaxhighlight> | + | </syntaxhighlight>--> |
− | --> | + | * Exercício 3: O que acontece se um dos threads é colocado para dormir? Todos os demais threads param a sua execução. |
− | *Exercício 3: O que acontece se um dos threads é colocado para dormir? Todos os demais threads param a sua execução. | ||
− | *Exercício 4: Note que um thread somente deixa a execução para outro thread de forma explícita. Será que é possível realizar um escalonamento de threads de forma similar ao que o kernel faz com os processos? Ver http://www.cplusplus.com/forum/unices/6452/ | + | * Exercício 4: Note que um thread somente deixa a execução para outro thread de forma explícita. Será que é possível realizar um escalonamento de threads de forma similar ao que o kernel faz com os processos? Ver http://www.cplusplus.com/forum/unices/6452/ |
{{collapse bottom}} | {{collapse bottom}} | ||
Linha 1 212: | Linha 1 208: | ||
{{collapse bottom}} | {{collapse bottom}} | ||
− | =AULA 12 ?? - REMOTA - Dia | + | =AULA 12 ?? - REMOTA - Dia 3/04/2020= |
− | |||
==Objetivos/Conteúdos== | ==Objetivos/Conteúdos== | ||
− | **Conceito de Preempção | + | ** Conceito de Preempção |
− | **Critérios de Escalonamento | + | ** Critérios de Escalonamento |
− | *Algoritmos de Escalonamento | + | * Algoritmos de Escalonamento |
− | **FCFS | + | ** FCFS |
− | **Menor-Job-Primeiro | + | ** Menor-Job-Primeiro |
− | **Prioridades | + | ** Prioridades |
− | **Round Robin | + | ** Round Robin |
==Slides USados mna Aula== | ==Slides USados mna Aula== | ||
− | *Slides do Livro do Professor Maziero e do Prof.Arliones | + | ** Slides do Livro do Professor Maziero e do Prof.Arliones |
==Referências== | ==Referências== | ||
− | *Cap.51, 5.2 e 5.3 do Livro de Silberschatz | + | ** Cap.51, 5.2 e 5.3 do Livro de Silberschatz |
− | *[https://www.os-book.com/OS9/slide-dir/ Slides Silberschatz] | + | ** [https://www.os-book.com/OS9/slide-dir/ Slides Silberschatz] |
− | *[http://docente.ifsc.edu.br/andre.damato/sop2018/SOP2018-parte2.pdf Apresentação sobre Gerenciamento de Processos] | + | ** [http://docente.ifsc.edu.br/andre.damato/sop2018/SOP2018-parte2.pdf Apresentação sobre Gerenciamento de Processos] |
− | *Cap.6 do Livro do Prof.Maziero (http://wiki.inf.ufpr.br/maziero/doku.php?id=socm:start) | + | ** Cap.6 do Livro do Prof.Maziero (http://wiki.inf.ufpr.br/maziero/doku.php?id=socm:start) |
− | *https://www.geeksforgeeks.org/vector-in-cpp-stl/ | + | ** https://www.geeksforgeeks.org/vector-in-cpp-stl/ |
=AULA 13 ?? - REMOTA - Dia 14/04/2020= | =AULA 13 ?? - REMOTA - Dia 14/04/2020= | ||
Linha 1 524: | Linha 1 519: | ||
*Capítulos 3 e 4 do Silberschatz | *Capítulos 3 e 4 do Silberschatz | ||
− | =AULA SÍNCRONA - Dia | + | =AULA SÍNCRONA - Dia 26/5/2020= |
− | |||
==Objetivos== | ==Objetivos== | ||
Linha 1 532: | Linha 1 526: | ||
==Laboratório de libpthreads== | ==Laboratório de libpthreads== | ||
− | |||
− | |||
==Parte 1== | ==Parte 1== | ||
− | ;POSIX | + | ;POSIX ThreadsA API POSIX disponibiliza uma biblioteca de threads chamada pthread. As threads são implementadas pela estrutura ''pthread_t'', e manipuladas pelas funções (acesse as man-pages das chamadas para maiores detalhes): |
− | + | * ''pthread_create'': cria uma thread; | |
− | *''pthread_create'': cria uma thread; | + | * ''pthread_kill'': força a terminação de uma thread; |
− | *''pthread_kill'': força a terminação de uma thread; | + | * ''pthread_join'': sincroniza o final de uma thread (qual a diferença/semelhança com o ''wait'' que usamos para processos?); |
− | *''pthread_join'': sincroniza o final de uma thread (qual a diferença/semelhança com o ''wait'' que usamos para processos?); | + | * ''pthread_exit'': finaliza uma thread. |
− | *''pthread_exit'': finaliza uma thread. | ||
Para utilizar estas funções é necessário linkar o programa à libpthread (''-lpthread''). | Para utilizar estas funções é necessário linkar o programa à libpthread (''-lpthread''). | ||
==Parte 2== | ==Parte 2== | ||
− | |||
Exemplo básico de criação de threads do no [https://computing.llnl.gov/tutorials/pthreads/#Management POSIX Threads Programming] | Exemplo básico de criação de threads do no [https://computing.llnl.gov/tutorials/pthreads/#Management POSIX Threads Programming] | ||
− | + | # Implemente o programa em [https://computing.llnl.gov/tutorials/pthreads/samples/hello.c] | |
− | + | # Compilar com:<br /> | |
− | Implemente o programa em [https://computing.llnl.gov/tutorials/pthreads/samples/hello.c] | ||
− | |||
− | |||
− | Compilar com:<br> | ||
gcc -lpthread hello.c -o hello | gcc -lpthread hello.c -o hello | ||
− | + | # Executar:<br /> | |
− | |||
− | Executar:<br> | ||
./hello | ./hello | ||
− | |||
− | + | ||
+ | |||
==Parte 3== | ==Parte 3== | ||
− | |||
Como o Linux enxerga os pthreads | Como o Linux enxerga os pthreads | ||
− | + | # Faça uma modificação da função associada aos threads colocando um loop infinito após o Hello World | |
− | + | # O Linux "enxerga" estes threads? Confira com o comando htop | |
− | Faça uma modificação da função associada aos threads colocando um loop infinito após o Hello World | ||
− | |||
− | |||
− | O Linux "enxerga" estes threads? Confira com o comando htop | ||
− | |||
− | |||
− | |||
+ | ==Parte 4== | ||
Observe o código abaixo. | Observe o código abaixo. | ||
Linha 1 613: | Linha 1 590: | ||
− | + | # Execute o programa com o auxílio do programa time. Anote o tempo de execução.<br /> | |
− | |||
− | Execute o programa com o auxílio do programa time. Anote o tempo de execução.<br> | ||
time a.out | time a.out | ||
− | + | # Faça uma modificação para que o problema seja decomposto em threads explorando o número de cores físicos da sua máquina. | |
− | + | # Execute o programa com o auxílio do programa time. Compare com o tempo de execução sequencial.<br /> | |
− | Faça uma modificação para que o problema seja decomposto em threads explorando o número de cores físicos da sua máquina. | ||
− | |||
− | |||
− | Execute o programa com o auxílio do programa time. Compare com o tempo de execução sequencial.<br> | ||
time a.out | time a.out | ||
− | + | # Faça uma variação do programa multithread para que o thread associado a função main aguarde os demais threads computando então a soma de todos os elementos do vetor. Veja exemplo em [https://computing.llnl.gov/tutorials/pthreads/#Joining] | |
− | |||
− | Faça uma variação do programa multithread para que o thread associado a função main aguarde os demais threads computando então a soma de todos os elementos do vetor. Veja exemplo em [https://computing.llnl.gov/tutorials/pthreads/#Joining] | ||
− | |||
− | |||
− | |||
+ | ==Parte 5== | ||
Repita o procedimeto da parte 4 para explorar os cores lógicos. Existe ganho real? Discuta. | Repita o procedimeto da parte 4 para explorar os cores lógicos. Existe ganho real? Discuta. | ||
Linha 1 661: | Linha 1 628: | ||
*[https://www.os-book.com/OS9/slide-dir/index.html] | *[https://www.os-book.com/OS9/slide-dir/index.html] | ||
− | ==Laboratório de Race Condition, Algoritmo de Paterson e Mecanismos de Hardware== | + | ==Laboratório de Race Condition, Algoritmo de Paterson e Mecanismos de Hardware (9/6?)== |
− | + | # Implemente e execute várias o exemplo abaixo de 2 threads acessando uma área comum de dados (conta). Estime o valor final na variável conta. | |
− | |||
− | Implemente e execute várias o exemplo abaixo de 2 threads acessando uma área comum de dados (conta). Estime o valor final na variável conta. | ||
Compare os resultados obtidos. | Compare os resultados obtidos. | ||
Linha 1 745: | Linha 1 710: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | # Reimplemente o programa acima com controle da entrada e saída da região crítica usando o algoritmo de Paterson. | |
− | + | # Reimplemente o programa acima com controle da entrada e saída da região crítica usando uma instrução simulada de TEST AND SET. Notar que neste caso | |
− | Reimplemente o programa acima com controle da entrada e saída da região crítica usando o algoritmo de Paterson. | ||
− | |||
− | |||
− | Reimplemente o programa acima com controle da entrada e saída da região crítica usando uma instrução simulada de TEST AND SET. Notar que neste caso | ||
a atomicidade da instrução não é garantida. | a atomicidade da instrução não é garantida. | ||
− | |||
− | |||
=AULA SÍNCRONA - Dia 19/06/2020= | =AULA SÍNCRONA - Dia 19/06/2020= | ||
Linha 2 057: | Linha 2 016: | ||
;Faça uma proposta para estender o problema para dois produtores e um consumidor. | ;Faça uma proposta para estender o problema para dois produtores e um consumidor. | ||
− | =AULA SÍNCRONA - Dia | + | =AULA SÍNCRONA - Dia 30/06/2020= |
− | |||
==Objetivos== | ==Objetivos== | ||
− | *Conteúdos para avaliação | + | * Conteúdos para avaliação |
− | *Problema Produtor Consumidor | + | * Problema Produtor Consumidor |
==Referências== | ==Referências== | ||
− | *Livro Silberchatz: Cap.6 (versão 8) | + | * Livro Silberchatz: Cap.6 (versão 8) |
− | *Slides e Cap.11 e 12 do Livro do Prof.Maziero: Parte Semáforo e Mutex | + | * Slides e Cap.11 e 12 do Livro do Prof.Maziero: Parte Semáforo e Mutex |
==Conteúdos para Avaliação== | ==Conteúdos para Avaliação== | ||
Linha 2 097: | Linha 2 055: | ||
− | *ver como calcular os tempos de execução médio e tempo de espera; | + | * ver como calcular os tempos de execução médio e tempo de espera; |
− | |||
|} | |} | ||
− | |||
=AULA SÍNCRONA - Dia 4/08/2020= | =AULA SÍNCRONA - Dia 4/08/2020= | ||
− | |||
==Objetivos== | ==Objetivos== | ||
− | *Introdução a Gerência de Meméoria | + | * Introdução a Gerência de Meméoria |
− | **Vinculação de endereços lógicos aos físicos (8.1) | + | ** Vinculação de endereços lógicos aos físicos (8.1) |
− | **Swapping (8.2) | + | ** Swapping (8.2) |
==Referência== | ==Referência== | ||
− | |||
[https://www.os-book.com/OS8/OLD/os8e/slide-dir/PDF-dir/ch7.pdf Slides Cap.7 Silberschatz] | [https://www.os-book.com/OS8/OLD/os8e/slide-dir/PDF-dir/ch7.pdf Slides Cap.7 Silberschatz] | ||
Linha 2 164: | Linha 2 118: | ||
==Referência== | ==Referência== | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-17.pdf] | ||
*[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-15.pdf Slides Cap.16 MAziero] | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-15.pdf Slides Cap.16 MAziero] | ||
*[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-15.pdf Cap.15 Livro Maziero] | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-15.pdf Cap.15 Livro Maziero] | ||
Linha 2 178: | Linha 2 133: | ||
*Data 04/Set | *Data 04/Set | ||
*Sexta: revisamos PRoblemas Classicos | *Sexta: revisamos PRoblemas Classicos | ||
+ | |||
+ | =AULA SÍNCRONA - Dia 21/08/2020= | ||
+ | |||
+ | *Revisão Mecanismos de Coordenação - Preparação para Avaliação 2 | ||
+ | *Problemas Clássicos de Sincronização | ||
+ | |||
+ | ==Material de Referência== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-12.pdf Cap.12 Livro Maziero] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-12.pdf Slides Cap.12 Maziero] | ||
+ | *[https://www.os-book.com/OS8/OLD/os8e/slide-dir/PDF-dir/ch6.pdf Slides Silbeschatz Cap. Problemas Clássicos] | ||
+ | |||
+ | =AULA - Dia 29/08/2020= | ||
+ | |||
+ | *AVALIAÇÂO 2 | ||
+ | |||
+ | =AULA - Dia 1/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Conceituar Arquivos, DIretórios e Sistemas de Arquivos | ||
+ | *Atributos de Arquivos | ||
+ | *Operações sobre arquivos | ||
+ | |||
+ | ==ASSISTIR VÍDEO== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-video-22.mkv Vídeo Cap.22 do Livro do Prof.Maziero] | ||
+ | |||
+ | ==Tarefa == | ||
+ | |||
+ | *Ver questionário no SIGAA | ||
+ | |||
+ | =AULA - Dia 4/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Uso de Arquivos | ||
+ | **Operações sobre arquivos | ||
+ | **Formas de Acessos | ||
+ | **Permissões | ||
+ | **Travas | ||
+ | |||
+ | ==ReferÊncias== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-23.pdf Cap.23 - Livro Prof.Maziero] | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-23.pdf Slides Cap.23] | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-video-23.mkv Vídeo Cap.23] | ||
+ | |||
+ | ==TAREFA ANP== | ||
+ | |||
+ | VER NO SIGAA: TAREFA A3.1 - Permissionamento de Arquivos no Linux | ||
+ | |||
+ | ==Adicional== | ||
+ | |||
+ | *[https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/ Anatomia do ELF] | ||
+ | |||
+ | *[https://lwn.net/Articles/631631/ Como programas são executados no Linux] | ||
+ | |||
+ | *Ver Silberschatz: | ||
+ | **Interface de Sistema de Arquivos (cap.10) | ||
+ | **Conceito de Arquivo (10.1): | ||
+ | **Atributo de Arquivos (10.1.1), | ||
+ | **Operações sobre Arquivos (10.1.2), | ||
+ | **Tipos de Arquivos (10.1.3) e | ||
+ | **Estrutura de Arquivos (10.1.4) | ||
+ | **Métodos de Acesso (10.2) | ||
+ | **Acesso Sequencial (10.2.1) | ||
+ | **Acesso Direto (10.2.2) | ||
+ | **Outros métodos de acesso (10.2.3) | ||
+ | |||
+ | =AULA - Dia 8/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Implementação do Sistema de Arquivos | ||
+ | |||
+ | ==Material de ReferÊncia== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-24.pdf Cap.24 do Livro Prof.Maziero] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-24.pdf Slides Ca.24] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-video-25.mkv Vídeo Cap.24] | ||
+ | |||
+ | =AULA - Dia 11/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Implementação do Sistema de Arquivos (Continuação) | ||
+ | |||
+ | ==Material de ReferÊncia== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-24.pdf Cap.24 do Livro Prof.Maziero] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-24.pdf Slides Ca.24] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-video-25.mkv Vídeo Cap.24] | ||
+ | |||
+ | =AULA - Dia 15/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Subsistema de IO: Hardware de IO | ||
+ | *Avaliação 3 - Dia 25/09/2020 - Prova Objetiva (diferente para cada aluno - 50% Tarefa ANP) | ||
+ | *Recuperação da Avaliação 1 - Dia 2/10 | ||
+ | |||
+ | ==Referências== | ||
+ | |||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-19.pdf Cap.19] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-slides-19.pdf Slides Cap.19] | ||
+ | *[http://wiki.inf.ufpr.br/maziero/lib/exe/fetch.php?media=socm:socm-video-19.mkv Vídeo do Cap.19] | ||
+ | *Cap.Subsistemas de IO do Silberschatz | ||
+ | *[https://web.fe.up.pt/~pfs/aulas/so2020/proj/proj1.html proj1 2020 Universidade do Porto] | ||
+ | *[https://web.fe.up.pt/~pfs/aulas/so2020/ Link Para SOP2020 Universidade do Porto] | ||
+ | *[https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html] | ||
+ | |||
+ | =AULA - Dia 18/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Projeto Final: Parte 1 | ||
+ | |||
+ | |||
+ | ==Projeto Final== | ||
+ | |||
+ | Desenvolvimento do um Char Device Driver para Linux baseado em [https://web.fe.up.pt/~pfs/aulas/so2020/proj/proj1.html proj1 2020 Universidade do Porto] | ||
+ | O objetivo final do projeto é um serial device driver a ser testado entre duas VMs. | ||
+ | |||
+ | ==Etapa 1== | ||
+ | |||
+ | *Lab 1 - Instalação da VM com o CICA2 | ||
+ | *Lab 2 | ||
+ | **Driver Hello World Personalizado | ||
+ | |||
+ | =AULA - Dia 22/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Projeto Final: Parte 2 | ||
+ | *Lembrar que Sexta (25) será passada a AVAL.3 (questões objetivas) | ||
+ | |||
+ | ==PARTE 2 - ECHO DEVICE== | ||
+ | |||
+ | Seguir instruções de [https://web.fe.up.pt/~pfs/aulas/so2020/proj/proj2.html proj1 2020 Universidade do Porto] | ||
+ | |||
+ | Fazer: | ||
+ | -registro do major e minor number | ||
+ | -criação do device echo_device | ||
+ | -criação das funções open, read, write e close | ||
+ | |||
+ | =AULA - Dia 25/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Avaliação 3 | ||
+ | |||
+ | =AULA - Dia 29/09/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Rec. Aval 1 - Dia 6/10/2020 | ||
+ | *Projeto: Visão Geral de onde podemos chegar... | ||
+ | *Projeto Final: Parte 2 (continuação) | ||
+ | |||
+ | |||
+ | =AULA - Dia 2/10/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | <syntaxhighlight lang=cpp> | ||
+ | |||
+ | |||
+ | #include <stdio.h> | ||
+ | |||
+ | #define DIM_1 2 | ||
+ | #define DIM_2 3 | ||
+ | #define DIM_3 4 | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | int matA[DIM_1][DIM_2]={{2,5,7}, | ||
+ | {4,7,5} | ||
+ | }, | ||
+ | matB[DIM_2][DIM_3]={{7,5,6,4}, | ||
+ | {4,6,4,3}, | ||
+ | {9,2,2,1} | ||
+ | }, | ||
+ | matR[DIM_1][DIM_3] ={ | ||
+ | {0,0,0,0}, | ||
+ | {0,0,0,0} | ||
+ | }, | ||
+ | i,j,k; | ||
+ | |||
+ | |||
+ | for (i=0;i<DIM_1;i++) | ||
+ | for (j=0;j<DIM_3;j++) { | ||
+ | for (k=0;k<DIM_2;k++) | ||
+ | matR[i][j]=matR[i][j]+matA[i][k]*matB[k][j]; | ||
+ | printf("MatR[%d][%d] => %d \n", i, j, matR[i][j]); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | =AULA DIA Dia 9/10/2020= | ||
+ | |||
+ | =Objetivos= | ||
+ | |||
+ | *Acompanhamento Projeto Final | ||
+ | *Echo Driver | ||
+ | |||
+ | |||
+ | |||
+ | =AULA DIA Dia 13/10/2020= | ||
+ | |||
+ | ==Objetivos== | ||
+ | |||
+ | *Acompanhamento Projeto Final | ||
+ | *Lab. 3 Univ.Porto (https://web.fe.up.pt/~pfs/aulas/so2020/proj/proj3.html) | ||
+ | |||
+ | =Reconfigurar teclado do CICA2= | ||
+ | |||
+ | sudo dpkg-reconfigure console-data | ||
+ | |||
+ | Escolher o teclado abnt2 |
Edição atual tal como às 09h20min de 27 de outubro de 2020
AULA 1 - Dia 11/02/2020
Objetivos/Conteúdos
- Apresentação do Plano de Ensino
- Objetivos e Conteúdo Programático da Disciplina (ver SIGAA)
- Forma de Avaliação (ver SIGAA)
- Introdução a Sistemas Operacionais (Cap1. do Silberschatz)
- O que faz um sistema operacional (1.1)
- Organização e Arquitetura de um Sistema Computacional (1.2 e 1.3)
- Importância da Interrupção e Timers (1.2.1)
- Estrutura de Armazenamento (1.2.2)
- Estrutura de IO (1.2.3)
- Estrutura e Operações de um Sistema Operacional (1.4 e 1.5)
Material de Referência
- Apresentação sobre histórico visão geral e estruturas básicas de um SO
- Slides Silberschatz Oitava Edição
- Tradução Slides Silberschatz Cap1
- Tradução Slides Silberschatz Cap2
- Tradução Slides Silberschatz Cap3
- Tradução Slides Silberschatz Cap4
- Livro do Prof.Maziero
- Université Nice Sophia Antipolis
Arliones:
Leitura Recomendada
- Cap.1 do Silberschatz principalmente:
- 1.1 a 1.9
Exercícios Práticos de Apoio a Aula
Na sequência. com fins motivacionais, são apresentados alguns exercícios ilustrando conceitos de processos, arquivos e permissionamento.
-
Comando para ver todos os processos no linux:
$ ps aux
-
Colocar 2 processos se executando no contexto de um terminal e verificar número dos processos e então "destruí-los":
$ yes > /dev/null $ yes > /dev/null $ ps $ kill -9 <pid_yes> $ kill -9 <pid_yes>
Observe que dois processos foram criados a partir do programa "yes". Os processos associados ao terminal são visualizados e então destruídos. Tente destruir também o interpretador de comando (shell) associado ao terminal.
-
Criar um terminal adicional
$ xterm
Ir no terminal criado e listar os processos que se executam associados a este terminal. Verificar qual o dispositivo de entrada e saída associado a ele. Voltar ao terminal original e enviar uma mensagem. Destruir o terminal criado:
$ echo Alo Terminal > /dev/pts/2 $ kill -9 <pid_terminal>
-
Comunicação entre processos:
$ cat /etc/passwd | grep home | wc -l
-
Retirando a permissão de leitura de um arquivo em nível de usuário proprietário:
$ echo Alo Mundo > alfa.txt $ ls -l alfa.txt $ cat alfa.txt $ chmod u-r alfa.txt $ cat alfa.txt $ chmod u+r alfa.txt $ cat alfa.txt
AULA 2 - Dia 14/02/2020
Objetivos/Conteúdos
- Estruturas do Sistema Operacional (cap.2)
- Serviços do Sistema Operacional (2.1)
- Interfaces com Usuários (2.2)
- Chamadas do Sistema (2.3)
- Tipos de Chamadas de Sistema (2.4) ver Fig.2.8
- Chamadas de Controle de Processos
Material de Referência
- [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte1.pdf Apresentação sobre histórico visão geral
- [3]
Leitura Recomendada
- Cap.2 do Silberschatz principalmente:
- 2.1 a 2.8
Exercícios
- Estudar e executar o código em http://cs.lmu.edu/~ray/notes/gasexamples/ Detalhes das chamadas na arquitetura x86_64 ver em https://lwn.net/Articles/604287/
- Estudar e executar o código usando a função (em conformidade com a API POSIX) write() para o hello world:
#include <unistd.h> main() { write(1,"Alo Mundo\n",10); }
- Use o comando strace para verificar todas as chamadas de sistema dos programas acima.
-
DESAFIO 1: Estude a seção "Mixing C and Assembly Language" da http://cs.lmu.edu/~ray/notes/gasexamples/ e construa uma função meu_hello_world() usando o código em assembly do exercício inicial. Estude como poderia disponibilizar esta e outras funções de interface (a sua API) em uma biblioteca. Note que esta função deve ser chamada da forma:
main() { meu_hello_world(); }
Gere o assembly do código em C e discuta a diferença entre uma chamada de função e uma chamada de sistema.
-
DESAFIO 2: Estude o link http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ e melhore a função meu_hello_world para suportar uma mensagem adicional da forma:
#include <string.h> main() { char *p="Tudo bem com vocês?"; meu_hello_world(p, strlen(p)); }
Solução:
Solução modificado de http://cs.lmu.edu/~ray/notes/gasexamples/ .global meu_hello_world .text meu_hello_world: push %rdi # salva primeiro parâmetro push %rsi # salva segundo parâmetro mov $1, %rax # system call 1 é write mov $1, %rdi # file handle 1 é stdout mov $message, %rsi # endereço da string mov $13, %rdx # número de bytes da string syscall # chamada ao sistema pop %rdx # o que havia sido passado em rsi (número de bytes) é colocado em rdx pop %rsi # o que havia sido colocado em rdi (endereço da string) é colocado em rsi mov $1, %rax # system call 1 is write mov $1, %rdi # file handle 1 é stdout syscall # nova chamada ao sistema ret message: .ascii "Hello, World\n"
AULA 3 - Dia 18/02/2020
Objetivos/Conteúdos
- Interfaces com Usuários (2.2)
- Chamadas do Sistema (2.3)
- Tipos de Chamadas de Sistema (2.4) ver Fig.2.8
- Chamadas de Controle de Processos
AULA 4 - Dia 21/08/2020
Objetivos
- PARTE 2A: Gerenciamento de Processos (cap.3)
- 3.1.Conceito de Processo
- 3.2.Escalonamento de Processos
- 3.3.Operações sobre Processos (Laboratório Operações sobre Processos no Linux: Fork/Exec/Wait)
Material de Referência
- Slides do Cap.3 - Silberschatz
- Laboratório Fork/Exec/Wait
Exercícios de Demonstração
- Executar em um terminal o comando top. Em um outro terminal executar:
yes > /dev/null & yes > /dev/null &
- Parar um dos processos yes
kill -STOP <pid_yes>
- Continuar o processo
kill -CONT <pid_yes>
- Destruir todos
killall yes
AULA 5 - Dia 28/02/2020
Objetivos/Conteúdos
- Gerenciamento de Processos
- Conceito de Processo (3.1)
- O processo (3.1.1)
- Estado do Processo (3.1.2)
- Bloco de Controle de Processo (3.1.3)
- Threads (3.1.4)
- Scheduling (3.2)
- Filas de Scheduling (3.2.1)
- Schedulers
- Mudança de Contexto (3.2.3)
- Operações Sobre Processos (3.3)
- Conceito de Processo (3.1)
Slides desta aula
- Apresentação sobre Gerenciamento de Processos
- Capítulo 3 do livro do Silberschatz
Laboratório em Sala
https://wiki.sj.ifsc.edu.br/index.php/SOP29005-2019-1#Processos_no_Linux_-_Modificado_por_Eraldo
Exercícios de Demonstração
Processos no Linux Processos no Linux - Modificado por Eraldo
Processos no Linux
- Exercícios propostos pelo Prof.Arliones e Modificados por Eraldo
- Syscall FORK
- Em um terminal, execute "man fork"
- A função da API POSIX fork() aciona uma chamada de sistema (system call - syscall) que cria um novo processo duplicando o processo que realiza a chamada. O novo processo, chamado de filho, é uma cópia exata do processo criador, chamado de pai, exceto por alguns detalhes listados na manpage. O principal destes detalhes para nós agora é o fato de terem PIDs diferentes.
- O código dos dois processos (pai e filho) são idênticos;
- Os dados dos dois processos (pai e filho) são idênticos NO MOMENTO DA CRIAÇÃO;
- Execução do processo filho inicia na próxima instrução do programa (no retorno da chamada FORK);
- Não é possível saber qual dos processos (pai ou filho) retormará a execução primeiro - isto fica a cargo do excalonador do SO;
- Valores de retorno da chamada FORK:
- (-1): erro na criação do processo (ex.: memória insuficiente);
- (0): em caso de sucesso, este é o valor de retorno recebido pelo processo filho;
- (>0): em caso de sucesso, este é o valor de retorno recebido pelo processo pai;
- Syscall JOIN
- A syscall JOIN é implementada no POSIX pela função wait(). Execute "man wait".
- Além da função wait(), há também waitpid() e waitid();
- Todas estas syscalls são utilizadas para aguardar por mudanças no estado de um processo filho e obter informações sobre o processo filho cujo estado tenha mudado. São consideradas mudanças de estado: o filho terminou; o filho foi finalizado por um sinal (ex.: kill); o filho foi retomado por um sinal (ex.: alarme);
- A chamada wait também libera os recursos do processo filho que termina;
- wait(): esta função suspende a execução do processo chamador até que UM DOS SEUS FILHOS finalize;
- waitpid(): suspende a execução do processo chamador até que UM FILHO ESPECÍFICO finalize;
- Syscall EXEC
- A syscall EXEC é implementada no POSIX pela família de funções exec(). Execute "man exec".
- As principais funções da família são execl(), execlp() e execvp();
- Todas estas funções são, na realidade, front-ends (abstrações) para a syscall execve. Esta syscall substitui a imagem do processo corrente (aquele que chama a syscall) pela a imagem de um novo processo;
- Os parâmetros passados a estas funções são, basicamente, o nome de um arquivo com a imagem do programa a ser executado (um binário de um programa), e uma lista de parâmetros a serem passados a este novo programa;
- Exemplos POSIX utilizando fork/wait/exec
- Exemplo 1: fork/wait básico
// ex1: fork/wait básico #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { int pid, status; pid = fork(); if(pid == -1) // fork falhou { perror("fork falhou!"); exit(-1); } else if(pid == 0) // Este é o processo filho { printf("processo filho\t pid: %d\t pid pai: %d\n", getpid(), getppid()); exit(0); } else // Este é o processo pai { wait(&status); printf("processo pai\t pid: %d\t pid pai: %d\n", getpid(), getppid()); exit(0); } }
arliones@socrates:~/tmp$ gcc ex1.c -o ex1 arliones@socrates:~/tmp$ ./ex1 processo filho pid: 27858 pid pai: 27857 processo pai pid: 27857 pid pai: 5337 arliones@socrates:~/tmp$
- Exemplo 2: processos pai e filho compartilham código, mas não dados.
// ex2: fork/wait "compartilhando" dados // ex2: fork/wait "compartilhando" dados #include <sys/types.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { int pid, status, k=0; printf("processo %d\t antes do fork\n", getpid()); pid = fork(); printf("processo %d\t depois do fork\n", getpid()); if(pid == -1) // fork falhou { perror("fork falhou!"); exit(-1); } else if(pid == 0) // Este é o processo filho { k += 1000; printf("processo filho\t pid: %d\t K: %d \t endereço K: %p\n", getpid(), k, &k); exit(0); } else // Este é o processo pai { wait(&status); // espera o filho terminar k += 10; printf("processo pai\t pid: %d\t K: %d \t endereço K: %p\n", getpid(), k, &k); exit(0); } k += 1000; printf("FIM processo %d\t K: %d\n", getpid(), k); exit(0); }
processo 17056 antes do fork processo 17056 depois do fork processo 17057 depois do fork processo filho pid: 17057 K: 1000 endereço K: 0x7ffd8923e318 processo pai pid: 17056 K: 10 endereço K: 0x7ffd8923e318
- Modificação no código: comentar linhas 23 e 30
- Analise os resultados e busque entender a diferença.
- Perguntas e desafios.:
- Analisando os valores impressos de k pode-se dizer que os dados são compartilhados entre os dois processos?
- O endereço de k impresso é o mesmo nos dois processos. ISto não contradiz a afirmação anterior?
- Substitua o k por uma área criada dinâmicamente com o malloc (área de HEAP). Verifique se esta área é ou não compartilhada pelos processos.
- Exercício fork/wait
Excrever um programa C que cria uma árvore de 3 processos, onde o processo A faz um fork() criando um processo B, o processo B, por sua vez, faz um fork() criando um processo C. Cada processo deve exibir uma mensagem "Eu sou o processo XXX, filho de YYY", onde XXX e YYY são PIDs de processos. Utilizar wait() para garantir que o processo C imprima sua resposta antes do B, e que o processo B imprima sua resposta antes do A. Utilizar sleep() (man 3 sleep) para haver um intervalo de 1 segundo entre cada mensagem impressa.
- Use o comando pstree para verificar a árvore de processos criada.
Solução /* ex3: Excrever um programa C que cria uma arvore de 3 processos, onde o processo A faz um fork() criando um processo B, o processo B, por sua vez, faz um fork() criando um processo C. Cada processo deve exibir uma mensagem "Eu sou o processo XXX, filho de YYY", onde XXX e YYY sao PIDs de processos. Utilizar wait() para garantir que o processo C imprima sua resposta antes do B, e que o processo B imprima sua resposta antes do A. Utilizar sleep() (man 3 sleep) para haver um intervalo de 1 segundo entre cada mensagem impressa.
- /
- include <sys/types.h>
- include <stdlib.h>
- include <stdio.h>
- include <unistd.h>
- include <sys/wait.h>
int main() {
int pid, status; pid = fork();
if(pid == -1) // fork falhou { perror("fork falhou!"); exit(-1); } else if(pid == 0) // Este é o processo filho { pid = fork(); if(pid == -1) { perror("fork falhou!"); exit(-1); } else if(pid == 0) // Este é o filho do filho { sleep(1); printf("Eu sou o processo C (PID %d), filho de %d\n", getpid(), getppid()); exit (0); } else { wait(&status); sleep(1); printf("Eu sou o processo B (PID %d), filho de %d\n", getpid(), getppid()); exit(0); } } else // Este é o processo pai { wait(&status); sleep(1); printf("Eu sou o processo A (PID %d), filho de %d\n", getpid(), getppid()); exit(0); }
}
</syntaxhighlight>
AULA 6 - Dia 03/03/2020
Objetivos/Conteúdos
- Processos
- Exercícios Fork/Exec
AULA 7 - Dia 06/03/2020
Objetivos/Conteúdos
- Processos
- Exercícios Fork/Exec
- Memória Compartilhada
Cap.3 - Seção 3.4 e 3.5
AULA 8 - Dia 10/03/2020
Objetivos/Conteúdos
- Memória Compartilhada
- Troca de Msgs
- Laboratório de Pipes
AULA 9 - Dia 13/03/2020
Objetivos/Conteúdos
- Questionário de REvisão
- Conceito de Threads (cap.4)
- Caracterização do contexto e chaveamento de contexto do thread
- Laboratório de Thread de Applicação
- Slides sobre Threads:
Questionário - Processos
- Conceitue processo. Descreva e explique cada uma das seções de um processo na memória.
- Faça um diagrama e explique os possíveis estados de um processo no sistema. O que produz a transição entre estados?
- O que é um Bloco de Controle de Processo? Quais informações ficam armazenadas neste bloco?
- Faça um diagrama mostrando a alternância entre dois processos na CPU. Indique o procedimento de salvamento e restauração do estado do PCB.
- Explique o que é multiprogramação e escalonamento de processos.
- O que é a fila de processos prontos?
- Diferencie um processo limitado por IO de um processo limitado por CPU.
- Diferencie escalonamento de longo prazo de escalonamento de curto prazo.
- Discuta o papel da interrupção na troca de contexto entre processos.
- Explique como é o processo de criação de novos processos no UNIX/Linux através da chamada fork. O que acontece com a memória do novo processo?
- Explique como funciona a chamada exec no UNIX/Linux
- Explique como funciona a chamada wait no UNIX/Linux e como é possível retornar valores de um filho para o pai.
- Faça um esqueleto de um programa UNIX/Linux que ao se tornar processo cria 3 filhos e espera pela execução dos mesmos.
Questionário - Comunicação entre Processos
- Diferenciar processos independentes de processos cooperantes.
- Enumere e explique quatro razões para cooperação entre processos.
- A velocidade de processamento é uma das razões da cooperação entre processos. Discuta se um hardware com apenas uma CPU pode usufruir desta característica.
- Descreva os dois principais mecanismos de cooperação entre processos. Discuta a situação em que é possível usar a memória compartilhada e/ou a troca de mensagens.
- A memória compartilhada requer chamada ao sistema na sua operação? Discuta.
- Por que o processo de troca de mensagem deve ser mais lento que a memória compartilhada?
- Apresente em pseudocódigo uma proposta de funcionamento do problema do produtor consumidor usando memória compartilhada.
- A construção de uma solução para o problema produtor consumidor pode ser facilitado pelo uso da memória compartilhada? Discuta.
- Quais as duas operações básicas ma troca de mensagens? O que poderia motivar o uso de mensagens do tamanho fixo? Esta abordagem torna mais complexa a vida dos programadores?
- Enumere três métodos de implementação de uma lógica de ligação (link) entre processos.
- Explique o que é a comunicação direta em troca de mensagens. Descreva como são as duas primitivas de comunicação direta para esta abordagem e quais as 3 propriedades seguidas por esta comunicação.
- Descreva a variante assimétrica da troca direta de mensagens. O que muda em termos de primitiva de comunicação?
- Descreva o problema de hard-coding associado a nomeação direta e como pode ser contornado através da nomeação/comunicação indireta?
- O que é uma caixa postal? Como o Posix identifica uma caixa postal no caso de fila de mensagens?
- Dois processos podem usar mais do que uma caixa postal para se comunicar? Qual a condição para que isto ocorra?
- Descreva as duas operações básicas para a troca de mensagens com Caixa Postal.
- Descreva na comunicação indireta via Caixa Postal as 3 propriedades básicas.
- A questão do compartilhamento de caixas postais por múltiplos processos podem causar um problema na operação da recepção. Descreva quais as 3 possibilidades para contornar este problema.
- De que forma a caixa postal estando no espaço de endereçamento de um processo (propriedade) afeta a recepção por mensagens? Descreva.
- Quais as operações sobre uma caixa postal criada no espaço do sistema operacional deverão ser disponíveis? Descreva.
- A transmissão de mensagem pode ser com e sem bloqueio. Descreva as 4 possibilidades (síncrona/assíncrona).
- Discuta as 3 possibilidades de armazenamento de mensagens em buffer. Em que condições um remetente pode ser bloqueado?
Laboratório Threads Aplicação
Ver https://wiki.sj.ifsc.edu.br/index.php/SOP29005-2019-1#Threads_de_aplica.C3.A7.C3.A3o
Slides para esta aula
- Apresentação sobre Gerenciamento de Processos
- Slides do Capítulo 4 do livro do Silberschatz
AULA 10 ?? - REMOTA - Dia 24/03/2020
Objetivos/Conteúdos
- Webconf
- Revisão de Threads
- Laboratório de Thread de Applicação
Slides para esta aula
- Apresentação sobre Gerenciamento de Processos
- Slides do Capítulo 4 do livro do Silberschatz (
- Tradução Slides Silberschatz Cap4)
Threads de aplicação Threads de aplicação
O Linux, através da API POSIX, oferece um conjunto de funções que permite às aplicações manipular contextos, facilitando a vida do programador que quer implementar tarefas "simultâneas" dentro de um único processo, ou seja, threads. As seguintes funções e tipos estão disponíveis:
- getcontext(&a): salva o contexto na variável a;
- setcontext(&a): restaura um contexto salvo anteriormente na variável a;
- swapcontext(&a,&b): salva o contexto atual na variável a e restaura o contexto salvo anteriormente na variável b;
- makecontext(&a, ...): ajusta parâmetros internos do contexto salvo em a;
- ucontext_t: as variáveis a e b são do tipo ucontext_t. Este tipo armazena um contexto.
Busque mais informações sobre estas funções utilizando o programa manpage do Linux (ex.: man getcontext).
Estude o código no arquivo pingpong.c abaixo e explique seu funcionamento.
#include <stdio.h> #include <stdlib.h> #include <ucontext.h> #define STACKSIZE 32768 /* tamanho de pilha das threads */ /* VARIÁVEIS GLOBAIS */ ucontext_t cPing, cPong, cMain; /* Funções-comportamento das Tarefas */ void f_ping(void * arg) { int i; printf("%s iniciada\n", (char *) arg); for (i=0; i<4; i++) { printf("%s %d\n", (char *) arg, i); swapcontext(&cPing, &cPong); } printf("%s FIM\n", (char *) arg); swapcontext(&cPing, &cMain); } void f_pong(void * arg) { int i; printf("%s iniciada\n", (char *) arg); for (i=0; i<4; i++) { printf("%s %d\n", (char *) arg, i); swapcontext(&cPong, &cPing); } printf("%s FIM\n", (char *) arg); swapcontext(&cPong, &cMain); } /* MAIN */ int main(int argc, char *argv[]) { char *stack; printf ("Main INICIO\n"); getcontext(&cPing); stack = malloc(STACKSIZE); if(stack) { cPing.uc_stack.ss_sp = stack ; cPing.uc_stack.ss_size = STACKSIZE; cPing.uc_stack.ss_flags = 0; cPing.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext(&cPing, (void*)(*f_ping), 1, "\tPing"); getcontext(&cPong); stack = malloc(STACKSIZE); if(stack) { cPong.uc_stack.ss_sp = stack ; cPong.uc_stack.ss_size = STACKSIZE; cPong.uc_stack.ss_flags = 0; cPong.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext (&cPong, (void*)(*f_pong), 1, "\tPong"); swapcontext(&cMain, &cPing); swapcontext(&cMain, &cPong); printf("Main FIM\n"); exit(0); }
- Exercício 1: Primeiramente compile e execute o código. Agora estude o código e entenda completamente o seu funcionamento. Explique em DETALHES o código, comentando todas as linhas. Na seção de diagrama do seu relatório, desenhe um diagrama de funcionamento do código para mostrar exatamente como acontece a troca de contexto entre as threads.
- Exercício 2: Acrescente um procedimento f_new que receba 4 strings como parâmetros e imprima todas na tela. Antes do final da execução do main faça uma mudança de contexto para chamar o procedimento criado.
- Exercício 3: O que acontece se um dos threads é colocado para dormir? Todos os demais threads param a sua execução.
- Exercício 4: Note que um thread somente deixa a execução para outro thread de forma explícita. Será que é possível realizar um escalonamento de threads de forma similar ao que o kernel faz com os processos? Ver http://www.cplusplus.com/forum/unices/6452/
AULA 11 ?? - REMOTA - Dia 27/03/2020
Objetivos/Conteúdos
- Rever Threads em nível de Aplicação
- Escalonamento de Threads de Aplicação
- Exemplo: Escalalonador semi-automático
Ainda Threads - Um escalonador semi-automático" Ainda Threads - Um escalonador semi-automático usando sinais
Neste laboratório serão aprimorados os threads em nível de aplicação vistos na aula anterior. Usaremos sinais do Unix/Linux para escalonar os threads via handlers.
Exemplo 1:
No Linux/Unix o kernel ou um processo podem enviar sinais para outros processos. Trata-se de uma notificação de que um evento ocorreu. O processo pode ter tratadores (handlers) para estes sinais de forma a tratá-los de forma assíncrona. Pode-se fazer uma analogia com a interrupção por hardware de um programa em execução. Um tratador da interrupção trata a causa da mesma (evento) e no final do tratador (handler) é restaurado o contexto do programa interrompido. Por exemplo, quando um filho se encerra, o pai recebe do kernel o sinal SIGCHLD.
No exemplo abaixo utilizamos o sinail USR1 de uso geral (disponível para o usuário). Associamos um handler a este sinal (sig_handler). O programa sendo executado, fica em loop no main(). Usando um outro terminal podemos enviar um sinal e verificar o efeito do mesmo.
#include<stdio.h> #include <stdlib.h> #include<signal.h> #include<unistd.h> void sig_handler(int signo) { int x; printf("Turma de SOP: recebido SIGUSR1\n"); } int main(void) { int x; if (signal(SIGUSR1, sig_handler) == SIG_ERR) { printf("\nProblemas com SIGUSR1\n"); exit(-1); } // Loop eterno dormindo 1s while(1) { sleep(1); } return 0; }
Fazer no terminal:
ps aux
anotar o pid do processo e enviar o sinal:
kill -USR1 pid
Exemplo 2:
O programa anterior é aprimorado para começar a executar um thread Ping similar a aula anterior. Ainda não existe escalonamento dos threads. Somente o thread ping é executado. O sinal USR1 pode ser enviado para o processo interrompendo a execução do thread.
#include<stdio.h> #include <stdlib.h> #include<signal.h> #include<unistd.h> #include <ucontext.h> #define STACKSIZE 32768 /* tamanho de pilha das threads */ #define PING_ID 1 /* VARIÁVEIS GLOBAIS */ ucontext_t cPing, cPong, cMain; int curr_thread; /* Handler para tratar o sinal */ void sig_handler(int signo) { printf("Turma de SOP: recebido SIGUSR1\n"); } /* Funções-comportamento das Tarefas */ void f_ping(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void f_pong(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void preparar_contexto_ping() { char *stack; getcontext(&cPing); stack = malloc(STACKSIZE); if(stack) { cPing.uc_stack.ss_sp = stack ; cPing.uc_stack.ss_size = STACKSIZE; cPing.uc_stack.ss_flags = 0; cPing.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext(&cPing, (void*)&f_ping, 1, "\tPing"); } void preparar_contexto_pong() { char *stack; getcontext(&cPong); stack = malloc(STACKSIZE); if(stack) { cPong.uc_stack.ss_sp = stack ; cPong.uc_stack.ss_size = STACKSIZE; cPong.uc_stack.ss_flags = 0; cPong.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext (&cPong, (void*)&f_pong, 1, "\tPong"); } int main(void) { int x; printf ("Main INICIO\n"); preparar_contexto_ping(); preparar_contexto_pong(); if (signal(SIGUSR1, sig_handler) == SIG_ERR) { printf("\nProblemas com SIGUSR1\n"); exit(-1); } curr_thread=PING_ID; swapcontext(&cMain, &cPing); // loop eterno que nunca é executado while(1) { sleep(1); } return 0; }
Enviar o sinal USR1 para ver o efeito.
Exemplo 3:
Neste exemplo preparamos o handler para chavear o contexto de ping para pong e vice-versa. A cada USR1 recebido será realizada a troca de contexto.
#include<stdio.h> #include <stdlib.h> #include<signal.h> #include<unistd.h> #include <ucontext.h> #define STACKSIZE 32768 /* tamanho de pilha das threads */ #define PING_ID 1 #define PONG_ID 2 /* VARIÁVEIS GLOBAIS */ ucontext_t cPing, cPong, cMain; int curr_thread; /* Handler para tratar o sinal */ void sig_handler(int signo) { printf("Turma de SOP: recebido SIGUSR1\n"); if (curr_thread==PING_ID) { curr_thread=PONG_ID; swapcontext(&cPing, &cPong); } else { curr_thread=PING_ID; swapcontext(&cPong, &cPing); } } /* Funções-comportamento das Tarefas */ void f_ping(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void f_pong(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void prepara_contexto_ping() { char *stack; getcontext(&cPing); stack = malloc(STACKSIZE); if(stack) { cPing.uc_stack.ss_sp = stack ; cPing.uc_stack.ss_size = STACKSIZE; cPing.uc_stack.ss_flags = 0; cPing.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext(&cPing, (void*)&f_ping, 1, "\tPing"); } void prepara_contexto_pong() { char *stack; getcontext(&cPong); stack = malloc(STACKSIZE); if(stack) { cPong.uc_stack.ss_sp = stack ; cPong.uc_stack.ss_size = STACKSIZE; cPong.uc_stack.ss_flags = 0; cPong.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext (&cPong, (void*)&f_pong, 1, "\tPong"); } int main(void) { int x; printf ("Main INICIO\n"); prepara_contexto_ping(); prepara_contexto_pong(); if (signal(SIGUSR1, sig_handler) == SIG_ERR) { printf("\nProblemas com SIGUSR1\n"); exit(-1); } curr_thread=PING_ID; swapcontext(&cMain, &cPing); // A long long wait so that we can easily issue a signal to this process while(1) { sleep(1); } return 0; }
Exercício: Use o comando htop para verificar como estes threads são vistos pelo SOP.
Exercício: Tente analisar as pilhas dos threads e verificar sob qual pilha o handler se executa.
Exercício 4:
Neste ponto associamos um timer ao handler com o apoio do sinal ALRM. Agora os threads são escalonados automaticamente.
#include<stdio.h> #include <stdlib.h> #include<signal.h> #include<unistd.h> #include <ucontext.h> #include <sys/time.h> #define STACKSIZE 32768 /* tamanho de pilha das threads */ #define PING_ID 1 #define PONG_ID 2 #define TIME_SLICE 5 /* VARIÁVEIS GLOBAIS */ ucontext_t cPing, cPong, cMain; int curr_thread; /* Handler para tratar o sinal */ void sig_handler(int signo) { printf("SOP da Turma 2020-1: recebido SIGALRM\n"); alarm(TIME_SLICE); if (curr_thread==PING_ID) { curr_thread=PONG_ID; swapcontext(&cPing, &cPong); } else { curr_thread=PING_ID; swapcontext(&cPong, &cPing); } } /* Funções-comportamento das Tarefas */ void f_ping(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void f_pong(void * arg) { int i=0; printf("%s iniciada\n", (char *) arg); for (;;) { printf("%s %d\n", (char *) arg, i++); sleep(1); } printf("%s FIM\n", (char *) arg); } void preparar_contexto_ping() { char *stack; getcontext(&cPing); stack = malloc(STACKSIZE); if(stack) { cPing.uc_stack.ss_sp = stack ; cPing.uc_stack.ss_size = STACKSIZE; cPing.uc_stack.ss_flags = 0; cPing.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext(&cPing, (void*)(*f_ping), 1, "\tPing"); } void preparar_contexto_pong() { char *stack; getcontext(&cPong); stack = malloc(STACKSIZE); if(stack) { cPong.uc_stack.ss_sp = stack ; cPong.uc_stack.ss_size = STACKSIZE; cPong.uc_stack.ss_flags = 0; cPong.uc_link = 0; } else { perror("Erro na criação da pilha: "); exit(1); } makecontext (&cPong, (void*)(*f_pong), 1, "\tPong"); } void preparar_handler() { if (signal(SIGALRM, sig_handler) == SIG_ERR) { printf("\nProblemas com SIGUSR1\n"); exit(-1); } alarm(TIME_SLICE); } int main(void) { int x; printf ("Main INICIO\n"); preparar_contexto_ping(); preparar_contexto_pong(); preparar_handler(); curr_thread=PING_ID; //ajusta primeiro thread swapcontext(&cMain, &cPing); //nunca mais volta... return 0; }
Exercício Proposto 5
Refinar o handler de chaveamento de threads para que permita escalonar N f_pings, onde N será passado na linha de comando. Sugestão: criar uma fila ou vetor de identificadores de threads.
AULA 12 ?? - REMOTA - Dia 3/04/2020
Objetivos/Conteúdos
- Conceito de Preempção
- Critérios de Escalonamento
- Algoritmos de Escalonamento
- FCFS
- Menor-Job-Primeiro
- Prioridades
- Round Robin
Slides USados mna Aula
- Slides do Livro do Professor Maziero e do Prof.Arliones
Referências
- Cap.51, 5.2 e 5.3 do Livro de Silberschatz
- Slides Silberschatz
- Apresentação sobre Gerenciamento de Processos
- Cap.6 do Livro do Prof.Maziero (http://wiki.inf.ufpr.br/maziero/doku.php?id=socm:start)
- https://www.geeksforgeeks.org/vector-in-cpp-stl/
AULA 13 ?? - REMOTA - Dia 14/04/2020
Objetivos/Conteúdos
- Exemplo do Escalonador RR
Código de Exemplo
- Criar um relógio global para as demonstraçoes de funcionamento da API que foi criada
/** User-level threads example. Orion Sky Lawlor, olawlor@acm.org, 2005/2/18 (Public Domain) */ #include <stdio.h> #include <stdlib.h> #include <ucontext.h> /* for makecontext/swapcontext routines */ #include <queue> /* C++ STL queue structure */ #include <vector> #include<signal.h> #include<unistd.h> #include <ucontext.h> #include <sys/time.h> #define TIME_SLICE 1 typedef void (*threadFn)(void); class thread_cb { // bloco de controle do thread int id_thread; public: ucontext_t contexto; //metodos que manipulam o thread control block thread_cb(threadFn p, int id) //construtor { int stackLen=4*1024; char *stack=new char[stackLen]; getcontext(&contexto); contexto.uc_stack.ss_sp=stack; contexto.uc_stack.ss_size=stackLen; contexto.uc_stack.ss_flags=0; makecontext(&contexto,p,0); id_thread = id; }; ucontext_t *get_context() { return &contexto; }; }; std::queue<class thread_cb *> ready_pool; // fila de pronto int id_thread = 0; int id1,id2,id3; class thread_cb *curr_thread=NULL; int add_thread(threadFn func) //criar thread e retornar o id do thread criad { class thread_cb *p = new thread_cb(func, ++id_thread); ready_pool.push(p); return id_thread; } void dispatcher(ucontext_t *old_task, ucontext_t *new_task) { if (old_task!=NULL) swapcontext(old_task, new_task); else setcontext(new_task); } void scheduler_rr() { class thread_cb *next,*last; if(curr_thread!=NULL) { printf("Aqui\n"); ready_pool.push(curr_thread); last=curr_thread; next=ready_pool.front(); ready_pool.pop(); curr_thread=next; dispatcher(last->get_context(), curr_thread->get_context()); } else { next=ready_pool.front(); ready_pool.pop(); curr_thread = next; dispatcher(NULL, next->get_context()); } } void sig_handler(int signo) { printf("SOP da Turma 2019-2: recebido SIGALRM\n"); alarm(TIME_SLICE); if (ready_pool.empty()) { printf("Nothing more to run!\n"); exit(0); } scheduler_rr(); } void preparar_handler() { if (signal(SIGALRM, sig_handler) == SIG_ERR) { printf("\nProblemas com SIGUSR1\n"); exit(-1); } alarm(TIME_SLICE); } void runA(void) { int x=1; for (;;) { x++; printf("Thread A x=%d\n", x); } } void runB(void) { int x=1; for (;;) { x++; printf("Thread B x=%d\n", x); if(x>90000000L) yield_thread(); // abandonar a CPU } } void runC(void) { int x=1; for (;;) { x++; printf("Thread B x=%d\n", x); if (x>1000000L) //consultar um timer global del_thread(id2); } } main() { id1 = add_thread(runA); id2 = add_thread(runB); id3 = add_thread(runC); preparar_handler(); for(;;); }
AULA 14 ?? - REMOTA - Dia 15/04/2020
Objetivos/Conteúdos
- aula somte para dúvidas...
AULA 15 ?? - REMOTA - Dia 17/04/2020
Objetivos/Conteúdos
- Mecanismos de Sncronização
Material de Referência
- Slides Silberschatz (tradução Prof.Cristiano Costa)
- Slides Cap.10 Livro Prof.Maziero
- Cap.10 Livro Prof.Maziero
Exemplo de remoção de itens de uma lista do stl
#include <list> #include <iostream> using namespace std; int main() { struct tcb{ int id; } *p1,*p2,*p3; p1=new struct tcb; p1->id=3; p2=new struct tcb; p2->id=4; p3=new struct tcb; p3->id=7; list<struct tcb *> minhalista{ p1,p2,p3 }; list<struct tcb *>::iterator it; it= minhalista.begin(); while(it != minhalista.end()) { if ((*it)->id==4) { it = minhalista.erase(it); } else it++; } //imprimindo os ids de quem sobrou it= minhalista.begin(); while(it != minhalista.end()) { cout << "ID = " << (*it)->id << "\n"; it++; } return 0; }
AULA 16 ?? - REMOTA - Dia 24/04/2020
Objetivos/Conteúdos
- Mecanismos de Sncronização
- Conceito de Condição de Corrida
- Conceito de Exclusão Mútua e Seção Crítica
Material de Referência
- Slides Silberschatz (tradução Prof.Cristiano Costa)
- Slides Cap.10 Livro Prof.Maziero
- Cap.10 Livro Prof.Maziero
AULA 17 ?? - NÃO SÍNCRONA- Dia 28/04/2020
Objetivos/Conteúdos
- Mecanismos de Sincronização
- Race Condition
- Exclusão Mútua
- Soluções Triviais
- Algoritmo de Peterson
- Instruções Atômicas
Material de Referência
Vídeos elaborados pelo Prof.Eraldo usando os slides/Capítulo 10 do Livro Prof. Carlos Maziero
- Race Condition
- Exclusão Mútua
- Algoritmo de Peterson e Instruções Atômicas
- Exclusão Mútua usando Instrução Swap
REUNIÃO - Dia 19/05/2020
- ANPs
AULA - SÍNCRONA- Dia 22/5/2020
Objetivos
- Revisão de Sistema Computacional (1.2 e 1.3 do Livro do Silberchatz)
- Revisão de Serviços do Sistema Operacional
- Revisão: PARTE 2A: Gerenciamento de Processos (cap.3 Silberchatz ed.8)
- 3.1.Conceito de Processo (seção do livro)
- 3.2.Escalonamento de Processos (seção do livro)
- 3.3.Operações sobre Processos (seção do livro)
- 4.1.Visão Geral de Threads (seção do livro)
AULA - NÃO SÍNCRONA - Dia 22/5/2020
Objetivos
- Revisão: PARTE 2A: Gerenciamento de Processos (cap.3 Silberchatz ed.8)
Material Sugerido para Revisão
- Aulas Prof.Isidro da Universidade do ABC:
- Capítulos 3 e 4 do Silberschatz
AULA SÍNCRONA - Dia 26/5/2020
Objetivos
- Uso da biblioteca libpthreads
- Revisão de conceitos associados a threads
Laboratório de libpthreads
Parte 1
- POSIX ThreadsA API POSIX disponibiliza uma biblioteca de threads chamada pthread. As threads são implementadas pela estrutura pthread_t, e manipuladas pelas funções (acesse as man-pages das chamadas para maiores detalhes)
- pthread_create: cria uma thread;
- pthread_kill: força a terminação de uma thread;
- pthread_join: sincroniza o final de uma thread (qual a diferença/semelhança com o wait que usamos para processos?);
- pthread_exit: finaliza uma thread.
Para utilizar estas funções é necessário linkar o programa à libpthread (-lpthread).
Parte 2
Exemplo básico de criação de threads do no POSIX Threads Programming
- Implemente o programa em [6]
- Compilar com:
gcc -lpthread hello.c -o hello
- Executar:
./hello
Parte 3
Como o Linux enxerga os pthreads
- Faça uma modificação da função associada aos threads colocando um loop infinito após o Hello World
- O Linux "enxerga" estes threads? Confira com o comando htop
Parte 4
Observe o código abaixo.
#include <stdio.h> #define TAM 3 long double vetor_A[TAM]; void calcular_elemento(int i) { double x; for (x=0;x<=100;x=x+0.0000001){ vetor_A[i] = vetor_A[i] + ((i+1)*x + (i+3))*0.0000001; } } int main() { int i; /* solução sequencial */ for (i=0;i<TAM;i++) { calcular_elemento(i); } }
- Execute o programa com o auxílio do programa time. Anote o tempo de execução.
time a.out
- Faça uma modificação para que o problema seja decomposto em threads explorando o número de cores físicos da sua máquina.
- Execute o programa com o auxílio do programa time. Compare com o tempo de execução sequencial.
time a.out
- Faça uma variação do programa multithread para que o thread associado a função main aguarde os demais threads computando então a soma de todos os elementos do vetor. Veja exemplo em [7]
Parte 5
Repita o procedimeto da parte 4 para explorar os cores lógicos. Existe ganho real? Discuta.
AULA SÍNCRONA - Dia 5/6/2020
Objetivos/Conteúdos
- Revisão de Mecanismos de Sincronização (já proposto em aula anterior)
- Race Condition
- Exclusão Mútua
- Soluções Triviais
- Algoritmo de Peterson
- Instruções Atômicas
- Laboratório
Material de Referência
Vídeos elaborados pelo Prof.Eraldo usando os slides/Capítulo 10 do Livro Prof. Carlos Maziero
- Race Condition
- Exclusão Mútua
- Algoritmo de Peterson e Instruções Atômicas
- Exclusão Mútua usando Instrução Swap
Slides do Livro do Silberschatz
Laboratório de Race Condition, Algoritmo de Paterson e Mecanismos de Hardware (9/6?)
- Implemente e execute várias o exemplo abaixo de 2 threads acessando uma área comum de dados (conta). Estime o valor final na variável conta.
Compare os resultados obtidos.
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 2 /* based on https://computing.llnl.gov/tutorials/pthreads/samples/join.c */ double conta=0; void *Thread1_DepositarConta(void *t) { int i; long tid; tid = (long)t; printf("Thread %ld iniciando...\n",tid); for (i=0; i<10000; i++){ conta = conta+1; } pthread_exit((void*) t); } void *Thread2_DepositarConta(void *t) { int i; long tid; tid = (long)t; printf("Thread %ld iniciando...\n",tid); for (i=0; i<10000; i++){ conta = conta+1; } pthread_exit((void*) t); } int main (int argc, char *argv[]) { pthread_t thread[NUM_THREADS]; pthread_attr_t attr; int rc; long t; void *status; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t=0; t<NUM_THREADS; t++) { printf("Main: criando threads %ld\n", t); if(t==1) rc = pthread_create(&thread[t], &attr, Thread1_DepositarConta, (void *)t); else rc = pthread_create(&thread[t], &attr, Thread2_DepositarConta, (void *)t); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); for(t=0; t<NUM_THREADS; t++) { rc = pthread_join(thread[t], &status); if (rc) { printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1); } printf("Main: esperando thread %ld having a status of %ld\n",t,(long)status); } printf("Main: Programa terminado - conta = %lf\n", conta); pthread_exit(NULL); }
- Reimplemente o programa acima com controle da entrada e saída da região crítica usando o algoritmo de Paterson.
- Reimplemente o programa acima com controle da entrada e saída da região crítica usando uma instrução simulada de TEST AND SET. Notar que neste caso
a atomicidade da instrução não é garantida.
AULA SÍNCRONA - Dia 19/06/2020
Objetivos
- Laboratório: Race Condition e Mutex
- Explorar o problema de Race Condition
- Resolver o problema de Race Condition com o Mutex
- Conceito de Semáforo
Laboratório Parte 1
Estude o código abaixo e infira qual o valor da conta ao final da execução do programa.
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 2 double conta=0; void *Thread1_DepositarConta(void *t) { int i; long tid; tid = (long)t; printf("Thread %ld iniciando...\n",tid); for (i=0; i<10000; i++){ conta = conta+1; } pthread_exit((void*) t); } void *Thread2_DepositarConta(void *t) { int i; long tid; tid = (long)t; printf("Thread %ld iniciando...\n",tid); for (i=0; i<10000; i++){ conta = conta+1; } pthread_exit((void*) t); } int main (int argc, char *argv[]) { pthread_t thread[NUM_THREADS]; pthread_attr_t attr; int rc; long t; void *status; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t=0; t<NUM_THREADS; t++) { printf("Main: criando threads %ld\n", t); if(t==1) rc = pthread_create(&thread[t], &attr, Thread1_DepositarConta, (void *)t); else rc = pthread_create(&thread[t], &attr, Thread2_DepositarConta, (void *)t); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); for(t=0; t<NUM_THREADS; t++) { rc = pthread_join(thread[t], &status); if (rc) { printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1); } printf("Main: esperando thread %ld having a status of %ld\n",t,(long)status); } printf("Conta = %lf\n", conta); return 0; }
Laboratório Parte 2
Proponha uma solução para o problema da Parte 1 usando uma solução trivial com BUSY WAIT. Quais os problemas de uma solução deste tipo? A ideia do busy wait seria algo do tipo:
while(busy); // entrada seção crítica busy=1; // conta = conta+1; busy=0; // saída seção crítica
Laboratório Parte 3
Proponha uma solução para o problema da Parte 1 usando uma solução baseada em mutex. Estude o mutex em [9]
Laboratório Parte 4
Teste a ideia do mutex servir como um lock para vários threads ou processos. Refaça o exercício da parte 3 para 10 threads =. Use uma única função de base para thread.
Material de Referência
AULA SÍNCRONA - Dia 23/06/2020
Objetivos
- Conceito de Semáforo e Mutex
- Uso de Semáforos intra processo
Laboratório
Nos sistemas POSIX, semáforos são implementados pelo tipo sem_t e manipulado através das funções (acesse as man-pages das chamadas para maiores detalhes):
- sem_init: inicializa um semáforo;
- sem_destroy: destroy um semáforo;
- sem_wait: implementa a operação p;
- sem_post: implementa a operação v.
Para utilizar estas funções é necessário linkar o programa à librt ou à libpthread (-lrt ou -lpthread).
Ver exemplo em [10].
- PARTE 1
Modifique o programa para usar um semáforo binário ao invés de um mutex em sua solução.
- PARTE 2
Refaça o exercício da aula anterior criando dois tipos de tarefas (i) tarefas escritoras (atualizando o saldo) e (ii) tarefas leitoras. Crie 10 tarefas leitoras mas limite o acesso a leitura para no máximo 3 tarefas por vez.
Material de Referência
- Selides Cap.11 do Livro do Prof.Maziero
- Cap.sobre Semáforos do Silberschatz
Avaliação 1
Data: 3/Julho 2020
Questionário - Processos
- Conceitue processo. Descreva e explique cada uma das seções de um processo na memória.
- Faça um diagrama e explique os possíveis estados de um processo no sistema. O que produz a transição entre estados?
- O que é um Bloco de Controle de Processo? Quais informações ficam armazenadas neste bloco?
- Faça um diagrama mostrando a alternância entre dois processos na CPU. Indique o procedimento de salvamento e restauração do estado do PCB.
- Explique o que é multiprogramação e escalonamento de processos.
- O que é a fila de processos prontos?
- Diferencie um processo limitado por IO de um processo limitado por CPU.
- Diferencie escalonamento de longo prazo de escalonamento de curto prazo.
- Discuta o papel da interrupção na troca de contexto entre processos.
- Explique como é o processo de criação de novos processos no UNIX/Linux através da chamada fork. O que acontece com a memória do novo processo?
- Explique como funciona a chamada exec no UNIX/Linux
- Explique como funciona a chamada wait no UNIX/Linux e como é possível retornar valores de um filho para o pai.
- Faça um esqueleto de um programa UNIX/Linux que ao se tornar processo cria 3 filhos e espera pela execução dos mesmos.
Questionário - Comunicação entre Processos
- Diferenciar processos independentes de processos cooperantes.
- Enumere e explique quatro razões para cooperação entre processos.
- A velocidade de processamento é uma das razões da cooperação entre processos. Discuta se um hardware com apenas uma CPU pode usufruir desta característica.
- Descreva os dois principais mecanismos de cooperação entre processos. Discuta a situação em que é possível usar a memória compartilhada e/ou a troca de mensagens.
- A memória compartilhada requer chamada ao sistema na sua operação? Discuta.
- Por que o processo de troca de mensagem deve ser mais lento que a memória compartilhada?
- Apresente em pseudocódigo uma proposta de funcionamento do problema do produtor consumidor usando memória compartilhada.
- A construção de uma solução para o problema produtor consumidor pode ser facilitado pelo uso da memória compartilhada? Discuta.
- Quais as duas operações básicas ma troca de mensagens? O que poderia motivar o uso de mensagens do tamanho fixo? Esta abordagem torna mais complexa a vida dos programadores?
- Enumere três métodos de implementação de uma lógica de ligação (link) entre processos.
- Explique o que é a comunicação direta em troca de mensagens. Descreva como são as duas primitivas de comunicação direta para esta abordagem e quais as 3 propriedades seguidas por esta comunicação.
- Descreva a variante assimétrica da troca direta de mensagens. O que muda em termos de primitiva de comunicação?
- Descreva o problema de hard-coding associado a nomeação direta e como pode ser contornado através da nomeação/comunicação indireta?
- O que é uma caixa postal? Como o Posix identifica uma caixa postal no caso de fila de mensagens?
- Dois processos podem usar mais do que uma caixa postal para se comunicar? Qual a condição para que isto ocorra?
- Descreva as duas operações básicas para a troca de mensagens com Caixa Postal.
- Descreva na comunicação indireta via Caixa Postal as 3 propriedades básicas.
- A questão do compartilhamento de caixas postais por múltiplos processos podem causar um problema na operação da recepção. Descreva quais as 3 possibilidades para contornar este problema.
- De que forma a caixa postal estando no espaço de endereçamento de um processo (propriedade) afeta a recepção por mensagens? Descreva.
- Quais as operações sobre uma caixa postal criada no espaço do sistema operacional deverão ser disponíveis? Descreva.
- A transmissão de mensagem pode ser com e sem bloqueio. Descreva as 4 possibilidades (síncrona/assíncrona).
- Discuta as 3 possibilidades de armazenamento de mensagens em buffer. Em que condições um remetente pode ser bloqueado?
AULA SÍNCRONA - Dia 26/06/2020
Objetivos
- Revisão do Conceito de Semáforo e Mutex
- Uso de Semáforos intra processo
- Problema Produtor Consumidor
Material de Referência
- Livro Silberchatz: Cap.6 (versão 8)
- Slides e Cap.11 do Livro do Prof.Maziero: Parte Semáforo e Mutex
Laboratório
Nos sistemas POSIX, semáforos são implementados pelo tipo sem_t e manipulado através das funções (acesse as man-pages das chamadas para maiores detalhes):
- sem_init: inicializa um semáforo;
- sem_destroy: destroy um semáforo;
- sem_wait: implementa a operação p;
- sem_post: implementa a operação v.
Para utilizar estas funções é necessário linkar o programa à librt ou à libpthread (-lrt ou -lpthread).
Ver exemplo em [11].
- PARTE 1
- Modifique o programa do laboratório anterior para usar um semáforo binário ao invés de um mutex em sua solução.
- PARTE 2
- Analise o código abaixo. Trata-se de uma implementação do problema produtor consumidor sem nenhum mecanismo de sincronização ou coordenação.
Identifique a seção crítica.
#include <stdio.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> #define BUFFER_SIZE 50 sem_t mutex; volatile char fim=1; char buffer[BUFFER_SIZE]; long disponivel=0; /* numero de itens ocupados no no buffer */ int in,out=0; int itens_prod=1; int soma_prod=0, soma_cons=0; void* produtor(void* arg) { char prod=0; volatile long aux; do { while(disponivel == BUFFER_SIZE) ; buffer[in] = prod; soma_prod = soma_prod + prod; prod = (prod+1) % 5; in = (in + 1) % BUFFER_SIZE; //sem_wait(&mutex); disponivel = disponivel + 1; //sem_post(&mutex); printf("produzidos = %d\n", itens_prod++); } while (itens_prod!=900000); sleep(5); //tempo para encerrar fim=0; printf("TOTAL produzido = %d\n", soma_prod); pthread_exit(NULL); } void* consumidor(void* arg) { char consumo, consumo_ant='a'; volatile long aux; do { while(disponivel == 0 && fim) ; if (fim==0) break; consumo = buffer[out]; soma_cons = soma_cons + consumo; out = (out + 1) % BUFFER_SIZE; //sem_wait(&mutex); disponivel = disponivel - 1; //sem_post(&mutex); printf("disponivel = %ld\n", disponivel); } while (fim); printf("TOTAL consumido = %d\n", soma_cons); pthread_exit(NULL); } int main() { int x; //sem_init(&mutex, 0, 1); pthread_t t1,t2; pthread_create(&t1,NULL,produtor,NULL); pthread_create(&t2,NULL,consumidor,NULL); printf("Tecle 1 e ENTER para FIM\n"); scanf("%d", &x); fim = 0; pthread_join(t1,NULL); pthread_join(t2,NULL); //sem_destroy(&mutex); return 0; }
- PARTE 3
- Usando semáforos e mutex (ou semáforo binário), faça uma proposta de solução do problema produtor consumidor.
- PARTE 4
- Faça uma proposta para estender o problema para dois produtores e um consumidor.
AULA SÍNCRONA - Dia 30/06/2020
Objetivos
- Conteúdos para avaliação
- Problema Produtor Consumidor
Referências
- Livro Silberchatz: Cap.6 (versão 8)
- Slides e Cap.11 e 12 do Livro do Prof.Maziero: Parte Semáforo e Mutex
Conteúdos para Avaliação
Tópico Referência Comentário Introdução e Estrutura do SIstema Operacional 1.1 a 1.8 Silberchatz
2.1 a 2.7 + Laboratório System Call*Papel da Interrupção e Timers para os SOPs;
- Conceito de multiprogramação, multitarefa e multiprocessamento;
Processos: Conceitos e IPC 3.1 a 3.5 + Laboratórios de Processos, Pipes e Memória Compartilhada Ver [12] Threads 4.1. a 4.4. + Laboratório de Threads: de aplicação e pthreads Escalonamento do Processos Cap.6 Livro Prof.Maziero (até 6.4.5)[13] *Ver métricas/critérios para escalonamento;
- ver como calcular os tempos de execução médio e tempo de espera;
AULA SÍNCRONA - Dia 4/08/2020
Objetivos
- Introdução a Gerência de Meméoria
- Vinculação de endereços lógicos aos físicos (8.1)
- Swapping (8.2)
Referência
AULA SÍNCRONA - Dia 7/08/2020
Objetivos
- Gerenciamento de Memória Contígua (8.2)
- Paginação (8.4)
- Agendar a nova (rec1) avaliação 1 - Sugestão: Disponibilizo na quarta que vem (dia 13/08) - Colocar ANPs complementares
- Agendar a Avaliação 2 ?
Referência
Slides Cap.7 Silberschatz [14]
AULA SÍNCRONA - Dia 11/08/2020
Objetivos
- Gerenciamento de Memória: Contígua, Paginação e Segmentação
- Conceito de TLB
- Hierarquia de Paginação
Referência
AULA SÍNCRONA - Dia 14/08/2020
Objetivos
- Técnicas para estender a memória RAM
- Algoritmos de escolha de páginas vítima
Referência
AULA SÍNCRONA - Dia 18/08/2020
Objetivos
- Técnicas para estender a memória RAM (continuação)
- Algoritmos de escolha de páginas vítima
- Ver ANP repassada na wiki
Referência
REcuperação A1
- Dia 28/08/2020
- ver conteúdo tabela acima
A2
- Coordenação de Processos
- Memória Virtual
- Data 04/Set
- Sexta: revisamos PRoblemas Classicos
AULA SÍNCRONA - Dia 21/08/2020
- Revisão Mecanismos de Coordenação - Preparação para Avaliação 2
- Problemas Clássicos de Sincronização
Material de Referência
AULA - Dia 29/08/2020
- AVALIAÇÂO 2
AULA - Dia 1/09/2020
Objetivos
- Conceituar Arquivos, DIretórios e Sistemas de Arquivos
- Atributos de Arquivos
- Operações sobre arquivos
ASSISTIR VÍDEO
Tarefa
- Ver questionário no SIGAA
AULA - Dia 4/09/2020
Objetivos
- Uso de Arquivos
- Operações sobre arquivos
- Formas de Acessos
- Permissões
- Travas
ReferÊncias
TAREFA ANP
VER NO SIGAA: TAREFA A3.1 - Permissionamento de Arquivos no Linux
Adicional
- Ver Silberschatz:
- Interface de Sistema de Arquivos (cap.10)
- Conceito de Arquivo (10.1):
- Atributo de Arquivos (10.1.1),
- Operações sobre Arquivos (10.1.2),
- Tipos de Arquivos (10.1.3) e
- Estrutura de Arquivos (10.1.4)
- Métodos de Acesso (10.2)
- Acesso Sequencial (10.2.1)
- Acesso Direto (10.2.2)
- Outros métodos de acesso (10.2.3)
AULA - Dia 8/09/2020
Objetivos
- Implementação do Sistema de Arquivos
Material de ReferÊncia
AULA - Dia 11/09/2020
Objetivos
- Implementação do Sistema de Arquivos (Continuação)
Material de ReferÊncia
AULA - Dia 15/09/2020
Objetivos
- Subsistema de IO: Hardware de IO
- Avaliação 3 - Dia 25/09/2020 - Prova Objetiva (diferente para cada aluno - 50% Tarefa ANP)
- Recuperação da Avaliação 1 - Dia 2/10
Referências
- Cap.19
- Slides Cap.19
- Vídeo do Cap.19
- Cap.Subsistemas de IO do Silberschatz
- proj1 2020 Universidade do Porto
- Link Para SOP2020 Universidade do Porto
- [16]
AULA - Dia 18/09/2020
Objetivos
- Projeto Final: Parte 1
Projeto Final
Desenvolvimento do um Char Device Driver para Linux baseado em proj1 2020 Universidade do Porto O objetivo final do projeto é um serial device driver a ser testado entre duas VMs.
Etapa 1
- Lab 1 - Instalação da VM com o CICA2
- Lab 2
- Driver Hello World Personalizado
AULA - Dia 22/09/2020
Objetivos
- Projeto Final: Parte 2
- Lembrar que Sexta (25) será passada a AVAL.3 (questões objetivas)
PARTE 2 - ECHO DEVICE
Seguir instruções de proj1 2020 Universidade do Porto
Fazer: -registro do major e minor number -criação do device echo_device -criação das funções open, read, write e close
AULA - Dia 25/09/2020
Objetivos
- Avaliação 3
AULA - Dia 29/09/2020
Objetivos
- Rec. Aval 1 - Dia 6/10/2020
- Projeto: Visão Geral de onde podemos chegar...
- Projeto Final: Parte 2 (continuação)
AULA - Dia 2/10/2020
Objetivos
#include <stdio.h> #define DIM_1 2 #define DIM_2 3 #define DIM_3 4 int main() { int matA[DIM_1][DIM_2]={{2,5,7}, {4,7,5} }, matB[DIM_2][DIM_3]={{7,5,6,4}, {4,6,4,3}, {9,2,2,1} }, matR[DIM_1][DIM_3] ={ {0,0,0,0}, {0,0,0,0} }, i,j,k; for (i=0;i<DIM_1;i++) for (j=0;j<DIM_3;j++) { for (k=0;k<DIM_2;k++) matR[i][j]=matR[i][j]+matA[i][k]*matB[k][j]; printf("MatR[%d][%d] => %d \n", i, j, matR[i][j]); } return 0; }
AULA DIA Dia 9/10/2020
Objetivos
- Acompanhamento Projeto Final
- Echo Driver
AULA DIA Dia 13/10/2020
Objetivos
- Acompanhamento Projeto Final
- Lab. 3 Univ.Porto (https://web.fe.up.pt/~pfs/aulas/so2020/proj/proj3.html)
Reconfigurar teclado do CICA2
sudo dpkg-reconfigure console-data
Escolher o teclado abnt2