SOP-EngTel 2018 2
Sistemas Operacionais
- Professor: André D'Amato
- Encontros: Segundas às 15:40 no LabCad e quintas às 13:30 no LabSid.
- Atendimento paralelo: Quarta de 12:00 ás 13:00 horas.
Conteúdo
Unidade 01: Introdução |
---|
Unidade 01: IntroduçãoVisão geral de funções, responsabilidades e estruturas de um SO
Arquitetura de sistemas operacionais e modelos de programação
|
Unidade 02: Processos |
---|
Unidade 02: ProcessosGerência de tarefas; contextos, processos e threads
Escalonamento de tarefas
Comunicação entre Processos
Coordenação de processos
|
Laboratórios
Um Exemplo de Uso "API Padrão POSIX" |
---|
Um Exemplo de Uso "API Padrão POSIX"
Qual o tamanho limite da memória que você conseguiu alocar?
Em sua opinião NMAP trata-se de uma syscall ou de uma API? Afinal API e syscall são a mesma coisa? Explique. void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
addr = Valor do início do mapeamento.
length = valor do tamanho da região a ser alocada.
prot = especificações de proteção da região alocada (consultar http://man7.org/linux/man-pages/man2/mmap.2.html).
flags = especificação do escopo e do tipo da região criada (exemplo publica ou privada, se é anônima ou não).
void* meu_malloc(size_t tamanho) {
void* addr = mmap(0, // addr
tamanho, // len
PROT_READ | PROT_WRITE, // prot
MAP_ANON | MAP_PRIVATE, // flags
-1, // filedes
0); // off
*(size_t*)addr = tamanho;
return addr;
}
int meu_free(void* addr) {
return munmap(addr - sizeof(size_t), (size_t) addr);
}
int soma(int *N1, int *N2){
return (*N1+*N2);
}
int main(int argc, char* argv[]) {
int* numero1 = meu_malloc(sizeof(int));
int* numero2 = meu_malloc(sizeof(int));
*numero1 = 10;
*numero2 = 20;
int resultado = soma(numero1, numero2);
printf("\n\n O resultado da soma é %d \n\n",resultado);
meu_free(numero1);
meu_free(numero2);
return 0;
}
|
Processos no Linux |
---|
Processos no Linux
// ex1: fork/wait básico
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.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$
// ex2: fork/wait "compartilhando" dados
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.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\n", getpid(), k);
exit(0);
}
else // Este é o processo pai
{
wait(&status);
k += 10;
printf("processo pai\t pid: %d\t K: %d\n", getpid(), k);
exit(0);
}
k += 10;
printf("processo %d\t K: %d\n", getpid(), k);
exit(0);
}
arliones@socrates:~/tmp$ gcc ex2.c -o ex2
arliones@socrates:~/tmp$ ./ex2
processo 18425 antes do fork
processo 18425 depois do fork
processo 18426 depois do fork
processo filho pid: 18426 K: 1000
processo pai pid: 18425 K: 10
arliones@socrates:~/tmp$
arliones@socrates:~/tmp$ gcc ex2.c -o ex2
arliones@socrates:~/tmp$ ./ex2
processo 32342 antes do fork
processo 32342 depois do fork
processo 32343 depois do fork
processo filho pid: 32343 K: 1000
processo 32343 K: 1010
processo pai pid: 32342 K: 10
processo 32342 K: 20
arliones@socrates:~/tmp$
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.
O status passado como parâmetro à função wait(&status) é, na verdade, o mecanismo de retorno de resultado do wait/waitpid. Ao retornar, esta variável contém informações sobre o resultado da execução do processo filho. Por exemplo, se um processo terminou normalmente (i.e., chamou exit), o comando WIFEXITED(status) retorna true. Este comando retorna false se o processo foi abortado (e.g., segmentation fault) ou morto (e.g., kill). Investigue no manual do wait no Linux (man wait) o funcionamento do comando WEXITSTATUS(status), e use-o para modificar o exercício anterior para calcular o 5!, sendo que cada processo pode executar apenas uma multiplicação.
|
Threads de aplicação |
---|
Threads de aplicaçãoEntregar um relatório impresso sobre a sua solução para o problema descrito. O relatório deve conter as seguintes seções:
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ícios sobre pipe e memória compartilhada | ||||
---|---|---|---|---|
PIPE e SH_MEMORY
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int fd[2], pipe_ret, filho;
char string[] = "Hello, pipe!\n";
char buffer[20];
pipe(fd);
if((filho = fork()) == -1)
{
perror("fork");
exit(1);
}
if(filho == 0)
{
/*Mandar string para a extremidade do pipe*/
exit(0);
}
else
{
/*Ler a mensagem no pipe*/
printf("Recebi este texto %s", buffer);
}
return(0);
}
|
Exercício (Algoritmo de Peterson) |
---|
Exercício (Algoritmo de Peterson)Exercício 1: Sincronize o código a seguir, de maneira que o processo pai imprima apenas os números impares e o processo filho os números pares. Para isso utilize o algoritmo de Peterson visto em aula. Utilize memória compartilhada para comunicação entre os processos. #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
main()
{
if (fork() != 0) { /* I am the parent */
int i;
for(i = 0;i < 10;i=i+2){
printf("Processo pai %d \n", i);
}
}
else { /*Child code */
int i;
for(i = 1;i < 10;i=i+2){
printf("Processo filho %d \n", i);
}
}
exit(0);
}
Explique seu raciocínio. |