SOP-EngTel 2018 1
Sistemas Operacionais
- Professor: André D'Amato
- Encontros: Segundas às 7:30 e sextas às 09:40 no Laboratório de Redes II.
- Atendimento paralelo: Quarta 9:30 às 10:30 na sala telecomunicações 1.
Material de aula
Slides
Listas de exercícios
As listas de exercícios são compostas por exercícios selecionados do livro do Silberschatz, 8a edição. Há 10 volumes deste livro na biblioteca do campus.
SILBERSCHATZ, Abraham; GALVIN, Peter; GAGNE, Greg. Fundamentos de sistemas operacionais. 8. ed. Rio de Janeiro: LTC, 2011. 515 p., il. ISBN 9788521617471.
Exercícios selecionados:
- Capítulo 1: 1.1-1.3, 1.6-1.8, 1.13, 1.14, 1.17, 1.22, 1.23, 1.25.
- Capítulo 2: 2.6-2.8, 2.12, 2.13, 2.17, 2.21, 2.26.
- Capítulo 3: 3.1, 3.3, 3.6, 3.7, 3.8, 3.10.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid, pid1; /* cria um processo-filho*/
pid = fork();
if (pid < 0) { /* um erro ocorreu */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* processo-filho */
pid1 = getpid();
printf("child: pid = %d \n",pid); /* A */
printf("child: pid1 = %d \n",pid1); /* B */
}else { /* processo-pai */
pid1 = getpid();
printf("parent: pid = %d \n",pid); /* C */
printf("parent: pid1 = %d \n",pid1); /* D */
wait(NULL);
}
return 0;
}
<code>
=Conteúdo=
{{collapse top| bg=lightyellow | expandir=true | Unidade 01: Introdução}}
== Unidade 01: Introdução ==
=== Apresentação do Curso ===
*[[SOP-EngTel_2018_1_plano| Plano de Ensino]]
*[[SOP2018_1_Cronograma | Cronograma]]
=== Visão geral de funções, responsabilidades e estruturas de um SO ===
* [https://www.youtube.com/watch?v=7LGKgdWtrqI Revolution OS]: documentário sobre Linux e software livre
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte1.pdf Apresentação sobre histórico visão geral e estruturas básicas de um SO]
* Capítulo 1 do livro do Silberschatz
=== Arquitetura de sistemas operacionais e modelos de programação ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte1.pdf Apresentação sobre histórico visão geral e estruturas básicas de um SO]
* Capítulo 2 do livro do Silberschatz
{{collapse bottom}}
{{collapse top| bg=lightyellow | expandir=true | Unidade 02: Processos}}
== Unidade 02: Processos ==
=== Gerência de tarefas; contextos, processos e threads ===
* [http://docente.ifsc.edu.br/andre.damato/sop2018/SOP2018-parte2.pdf Apresentação sobre Gerenciamento de Processos]
* Capítulo 3 do livro do Silberschatz
=== Escalonamento de tarefas ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte2.pdf Apresentação sobre Escalonamento de Processos]
* [http://courses.cs.vt.edu/csonline/OS/Lessons/Processes/index.html Animação de escalonamento de processos - Virginia Tech]
* Capítulo 5 do livro do Silberschatz.
* Estudo de caso: escalonador do Linux.
** [https://en.wikipedia.org/wiki/O(n)_scheduler Escalonador antigo O(n)].
** [https://en.wikipedia.org/wiki/O(1)_scheduler Escalonador do kernel 2.6 O(1)].
** [https://en.wikipedia.org/wiki/Completely_Fair_Scheduler Escalonador atual O(log(n))].
** [https://www.cs.columbia.edu/~smb/classes/s06-4118/l13.pdf Slides da University of Columbia sobre o mecanismo de escalonamento do Linux].
=== Comunicação entre Processos ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte3.pdf Apresentação sobre Comunicação entre Processos]
* Capítulo 3 do livro do Silberschatz.
=== Coordenação de processos ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte4.pdf Apresentação sobre Coordenação de Processos]
* Capítulos 6 e 7 do livro do Silberschatz.
* Curiosidade: [http://research.microsoft.com/en-us/um/people/mbj/mars_pathfinder/authoritative_account.html A inversão de prioridades na Mars Pathfinder]
{{collapse bottom}}
{{collapse top| bg=lightyellow | expandir=true | Unidade 03: Memória}}
== Unidade 03: Memória==
=== Introdução ao Gerenciamento de Memória ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte5.pdf Apresentação sobre Gerenciamento de Memória]
* Capítulo 8 do livro do Silberschatz.
=== Memória Principal ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte5.pdf Apresentação sobre Gerenciamento de Memória]
* Capítulo 8 do livro do Silberschatz.
=== Memória Virtual ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte5.pdf Apresentação sobre Gerenciamento de Memória]
* Capítulo 9 do livro do Silberschatz.
{{collapse bottom}}
{{collapse top| bg=lightyellow | expandir=true | Unidade 04: Armazenamento}}
== Unidade 04: Armazenamento ==
=== Interface do Sistema de Arquivos ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte6.pdf Apresentação sobre Gerenciamento de Arquivos]
* Capítulo 10 do livro do Silberschatz.
=== Implementação do Sistema de Arquivos ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte6.pdf Apresentação sobre Gerenciamento de Arquivos]
* Capítulo 11 do livro do Silberschatz.
=== Estrutura de Armazenamento em Massa ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte6.pdf Apresentação sobre Gerenciamento de Arquivos]
* Capítulo 12 do livro do Silberschatz.
=== Gerenciamento de Entrada e Saída ===
* [http://docente.ifsc.edu.br/arliones.hoeller/sop/slides/SOP29005-parte7.pdf Apresentação sobre Gerenciamento de Entrada e Saída]
* Capítulo 13 do livro do Silberschatz.
{{collapse bottom}}
=Laboratórios=
{{collapse top| bg=lightyellow | expandir=true | Um Exemplo de Uso "API Padrão POSIX"}}
== Um Exemplo de Uso "API Padrão POSIX" ==
;Referências
* Referência http://man7.org/linux/man-pages/man2/mmap.2.html
Crie uma função soma que receba 2 ponteiros referenciando posições na memória, criadas utilizando nmap(), de maneira que estas posições armazenem números inteiros. A função soma deverá retornar a soma dos números apontados em regiões da memória sem a utilização de nenhuma rotina da biblioteca do C, que não sejam definidas por APIs posix, para criação destas
regiões na memória (malloc, alloc, calloc). Após retornar o resultado da soma os devidos ponteiros deverão ser extintos da memória.
*'''Experimento 1:''' Aumente o tamanho da memória alocada até quando for possível.
Qual o tamanho limite da memória que você conseguiu alocar?
*'''Experimento 2:''' Mude o escopo para PROT_NONE, após executar e depurar o código explique o que aconteceu.
Em sua opinião NMAP trata-se de uma syscall ou de uma API? Afinal API e syscall são a mesma coisa? Explique.
<syntaxhighlight lang=cpp>
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 + sizeof(size_t);
}
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 (Atividade 1) |
---|
Processos no LinuxEntregar um relatório impresso sobre a sua solução para o problema descrito. O relatório deve conter as seguintes seções:
// 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 (Atividade 2) |
---|
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);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024
int main(int argc, char *argv[])
{
key_t key;
int shmid;
char *segmento;
int modo,filho;
/* Criar a chave: */
if (key == -1)
{
perror("ftok");
exit(1);
}
/*Criar o segmento */
if (shmid == -1) {
perror("shmget");
exit(1);
}
/*Vincula o segmento de memória á variável segmento*/
segmento = shmat(shmid, (void *)0, 0);
if (segmento == (char *)(-1)) {
perror("shmat");
exit(1);
}
if((filho = fork()) == -1)
{
perror("fork");
exit(1);
}
if(filho == 0) //Código do filho
{
exit(0);
}
else //Código do pai
{
}
/* detach from the segment: */
if (shmdt(segmento) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
|
Trocas de mensagens com pipes (Atividade 3) |
---|
Trocas de mensagens com pipes
Um mecanismo disponibilizado por sistemas UNIX para troca de mensagens entre processos é o PIPE. Pipes são mecanismos de comunicação indireta onde mensagens são trocadas através de mailboxes. Cada mailbox possui um identificador único, permitindo que processos identifiquem o canal de comunicação entre eles. O fluxo de mensagens em um Pipe é:
No UNIX, pipes são inicializados através da SystemCall pipe, que possui a seguinte sintaxe:
As primitivas send/receive para uso de um pipe no UNIX são implementadas por SystemCalls read/write, conforme segue:
Abaixo há um exemplo de programa criando um pipe e compartilhando os descritores entre dois processos (criados via fork()). #include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
char *message = "This is a message!!!" ;
main()
{
char buf[1024] ;
int fd[2];
pipe(fd); /*create pipe*/
if (fork() != 0) { /* I am the parent */
write(fd[1], message, strlen (message) + 1) ;
}
else { /*Child code */
read(fd[0], buf, 1024) ;
printf("Got this from MaMa!!: %s\n", buf) ;
}
}
|
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.
|
Exercício (Semáforos) |
---|
Exercício (Semáforos)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 Semáforos de acordo com a implementação em semaforo.h. 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);
}
SEMAFORO.H
int criar_semaforo(int val, int chave)
{
int semid ;
union semun {
int val;
struct semid_ds *buf ;
ushort array[1];
} arg_ctl ;
key_t ft = ftok("/tmp", chave);
semid = semget(ft,1,IPC_CREAT|IPC_EXCL|0666);
if (semid == -1) {
semid = semget(ft,1,0666);
if (semid == -1) {
perror("Erro semget()");
exit(1) ;
}
}
arg_ctl.val = val; //valor de início
if (semctl(semid,0,SETVAL,arg_ctl) == -1) {
perror("Erro inicializacao semaforo");
exit(1);
}
return(semid) ;
}
void P(int semid){
struct sembuf *sops = malloc(10*sizeof(int));
sops->sem_num = 0;
sops->sem_op = -1;
sops->sem_flg = 0;
semop(semid, sops, 1);
free(sops);
}
void V(int semid){
struct sembuf *sops = malloc(10*sizeof(int));
sops->sem_num = 0;
sops->sem_op = 1;
sops->sem_flg = 0;
semop(semid, sops, 1);
free(sops);
}
void sem_delete(int semid)
{
if (semctl(semid,0,IPC_RMID,0) == -1)
perror("Erro na destruicao do semaforo");
}
|
Programação concorrente |
---|
Programação concorrente
A 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):
Para utilizar estas funções é necessário linkar o programa à libpthread (-lpthread). A classe C++ abaixo abstrai estas operações: #ifndef __thread_h
#define __thread_h
#include <pthread.h>
#include <signal.h>
class Thread
{
public:
Thread(int ( * const entry)(int), int arg) {
if(pthread_create(&thread, 0, (void*(*)(void*))entry, (void *)arg))
thread = 0;
}
~Thread() {}
int join(int * status) { return pthread_join(thread, (void **)status); }
friend void exit(int status = 0) { pthread_exit((void *) status); }
private:
pthread_t thread;
};
#endif
A biblioteca pthread implementa um tipo pthread_mutex_t, que garante a exclusão mútua entre threads. Estes mutex são manipulados através das funções (acesse as man-pages das chamadas para maiores detalhes):
#ifndef __mutex_h
#define __mutex_h
#include <pthread.h>
class Mutex
{
public:
Mutex() {}
~Mutex() {}
void lock() { pthread_mutex_lock(&mut); }
bool try_lock() { return (pthread_mutex_trylock(&mut) == 0); } // true when succeeds.
void unlock() { pthread_mutex_unlock(&mut); }
private:
pthread_mutex_t mut;
};
#endif
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):
Para utilizar estas funções é necessário linkar o programa à librt ou à libpthread (-lrt ou -lpthread). A classe C++ abaixo abstrai estas operações:
#ifndef __semaphore_h
#define __semaphore_h
#include <semaphore.h>
class Semaphore
{
public:
Semaphore(int i = 1) { sem_init(&sem, 0, i); }
~Semaphore() { sem_destroy(&sem); }
void p() { sem_wait(&sem); }
void v() { sem_post(&sem); }
operator int()
{
int ret;
sem_getvalue(&sem, &ret);
return ret;
}
private:
sem_t sem;
};
#endif
Exemplo de uso do operator: Semaphore sem;
cout << (int)sem << endl;
O programa abaixo cria 5 threads, e cada uma destas threads atualiza uma variável global (memória compartilhada). #include <iostream>
#include "thread.h"
#define NUM_THREADS 5
using namespace std;
int saldo = 1000;
int AtualizaSaldo(int n)
{
int meu_saldo = saldo;
int novo_saldo = meu_saldo + n*100;
cout << "Novo saldo = " << novo_saldo << endl;
saldo = novo_saldo;
}
int main()
{
Thread * threads[NUM_THREADS];
for(int t = 0; t < NUM_THREADS; t++)
threads[t] = new Thread(&AtualizaSaldo, t+1);
cout << "Saldo final é " << saldo << "." << endl;
}
O programa abaixo manipula uma matriz de tamanho MxN (veja os defines para o tamanho da matriz). A função SumValues soma todos os valores em uma linha da matriz. A linha a ser somada é identificada pela variável i. Modifique o programa principal (main) nos locais indicados para:
#include <iostream>
#include "thread.h"
/* number of matrix columns and rows */
#define M 5
#define N 10
using namespace std;
int matrix[N][M];
Thread *threads[N];
/* thread function; it sums the values of the matrix in the row */
int SumValues(int i)
{
int n = i; /* number of row */
int total = 0; /* the total of the values in the row */
int j;
for (j = 0; j < M; j++) /* sum values in the "n" row */
total += matrix[n][j];
cout << "The total in row" << n << " is " << total << "." << endl;
/* terminate a thread and return a total in the row */
exit(total);
}
int main(int argc, char *argv[])
{
int i, j;
int total = 0; /* the total of the values in the matrix */
/* initialize the matrix */
for (i = 0; i < N; i++)
for (j = 0; j < M; j++)
matrix[i][j] = i * M + j;
/* create threads */
/* COLOQUE SEU CÓDIGO PARA CRIAR AS THREADS AQUI! */
/* wait for terminate a threads */
/* COLOQUE SEU CÓDIGO PARA PEGAR O SOMATÓRIO DE LINHAS E TOTALIZAR A SOMA DA MATRIZ AQUI! */
cout << "The total values in the matrix is " << total << endl;
return 0;
}
|
Problemas clássicos de coordenação de processos |
---|
Problemas clássicos de coordenação de processos
O problema clássico Produtor/Consumidor consiste em dois fluxos de execução (threads/processos), sendo que um dos fluxos (consumidor) só pode executar a partir do momento em que seus dados de entrada foram produzidos pelo outro fluxo (produtor).
#include <iostream>
#include "thread.h"
#include "semaphore.h"
using namespace std;
const int REP = 5;
char buffer;
Semaphore empty(1);
Semaphore full(0);
int producer(int n)
{
cout << "Producer was born!\n";
// Faltam, no laço abaixo:
// - uma chamada para empty.p()
// - uma chamada para full.v()
char data = -1;
for(int i = 0; i < REP; i++) {
cout << "Producing ...\n";
data = (char) i + 0x61;
buffer = data;
cout << "Stored... " << data << endl;
}
return n;
}
int consumer(int n)
{
cout << "Consumer was born!\n";
// Faltam, no laço abaixo:
// - uma chamada para full.p()
// - uma chamada para empty.v()
char data = -1;
for(int i = 0; i < REP; i++) {
cout << "Retrieving ...\n";
data = buffer;
cout << "Consumed... " << data << endl;
}
return n;
}
int main()
{
cout << "The Producer x Consumer Problem\n";
Thread prod(&producer, REP);
Thread cons(&consumer, REP);
int status;
prod.join(&status);
if(status == REP)
cout << "Producer went to heaven!\n";
else
cout << "Producer went to hell!\n";
cons.join(&status);
if(status == REP)
cout << "Consumer went to heaven!\n";
else
cout << "Consumer went to hell!\n";
return 0;
}
O problema clássico Jantar dos Filósofos consiste em que n fluxos (n filósofos) disputam n recursos (n talheres). No problema, para conseguir "jantar" (ou executar), cada filósofo precisa pegar dois talheres adjascentes a ele. Cada recurso é compartilhado por dois filósofos.
#include <iostream>
#include "thread.h"
#include "semaphore.h"
using namespace std;
const int DELAY = 10000000;
const int ITERATIONS = 5;
Semaphore chopstick[5];
int philosopher(int n)
{
cout << "Philosopher " << n << " was born!\n";
int first = (n < 4)? n : 0; // left for phil 0 .. 3, right for phil 4
int second = (n < 4)? n + 1 : 4; // right for phil 0 .. 3, left for phil 4
// Foram removidos do laço abaixo:
// - uma chamada para chopstick[first].p()
// - uma chamada para chopstick[second].p()
// - uma chamada para chopstick[first].v()
// - uma chamada para chopstick[second].v()
for(int i = 0; i < ITERATIONS; i++) {
cout << "Philosopher " << n << " thinking ...\n";
for(int i = 0; i < DELAY * 10; i++);
cout << "Philosopher " << n << " eating ...\n";
for(int i = 0; i < DELAY; i++);
}
return n;
}
int main()
{
cout << "The Dining-Philosophers Problem\n";
Thread * phil[5];
for(int i = 0; i < 5; i++)
phil[i] = new Thread(&philosopher, i);
int status;
for(int i = 0; i < 5; i++) {
phil[i]->join(&status);
if(status == i)
cout << "Philosopher " << i << " went to heaven!\n";
else
cout << "Philosopher " << i << " went to hell!\n";
}
return 0;
}
|