Vous êtes sur la page 1sur 24

FUNDAÇÃO EDUCACIONAL MONTES CLAROS

FACULDADE DE CIÊNCIA E TECNOLOGIA DE MONTES CLAROS

TRABALHO FINAL
THREADS E SEMÁFOROS

Nome: Diego Aquino, Paula Andréia e


Mateus Emiliano
Disciplina: Programação em Tempo
Real Assunto: Threads e Semáforos.
Professor: Aparecido Juneo
Turma: 7º Engenharia de Controle e
Automação.
Data: 24/06/2013

Montes Claros, MG- Junho - 2013.


1

THREADS E SEMÁFOROS

Trabalho apresentado pelos acadêmicos


do 7º período do curso de Engenharia de
Controle e Automação à Faculdade de
Ciência e Tecnologia de Montes Claros
como pré-requisito de avaliação na
disciplina de Programação em Tempo
Real.
2

SUMÁRIO

1. INTRODUÇÃO .................................................................................................................. 3
2. OBJETIVOS ...................................................................................................................... 4
3. METODOLOGIA............................................................................................................... 4
3.1 SOFTWARE UTILIZADO.................................................................................................... 4
3.2 PROBLEMA DO PRODUTOR CONSUMIDOR .............................................................. 4
3.3 JANTAR DOS FILÓSOFOS ............................................................................................... 8
3.4 SALÃO DE BARBEIRO .................................................................................................... 12
3.5 FUMANTES ......................................................................................................................... 15
3.6 MONTANHA RUSSA ........................................................................................................ 18
4. CONCLUSÃO ................................................................................................................. 22
5. REFERENCIAS BIBLIOGRAFICAS ........................................................................... 23
3

1. INTRODUÇÃO

A programação concorrente tem se tornado algo de fundamental importância


para os processos de computadores, sendo que dela se origina a capacidade de
execução de várias tarefas concorrentemente, gerando a sensação ao usuário
final de que estas estão sendo executadas simultaneamente.
As threads é uma das soluções fornecidas pela programação concorrente que
garante a execução paralela das tarefas, mas que além de tudo necessitam de
cuidados especiais durante a programação, para que o programa seja uma
solução viável e factível.
Métodos que garantem a funcionalidades das threads foram desenvolvidos e
empregados com o intuito de garantir ao programador uma solução que venha
ser eficaz em diversos processos, antecipando situações que podem ocorrer no
dia a dia durante a execução.
Veremos atreves de trabalho alguns métodos empregados para a
programação em tempo real, dos quais foram trabalhados em sala de aula, além
de empregar alguns dos clássicos problemas que ocorrem na programação.
4

2. OBJETIVOS

Com o objetivo de implementar alguns problemas clássicos da programação


em tempo real, temos como objetivo, através dos métodos aprendidos em sala,
realizar a programação no Dev C++ e executá-los verificando a eficácia de
alguns algoritmos desenvolvidos.

3. METODOLOGIA

3.1 SOFTWARE UTILIZADO

Para a realização e desenvolvimento do algoritmo proposto, utilizamos o


software Dev C++, plataforma capaz de realizar a programação e a compilação
do algoritmo, podendo através do mesmo identificar os possíveis erros
encontrados no algoritmo.

3.2 PROBLEMA DO PRODUTOR CONSUMIDOR

Neste problema temos a seguinte situação, onde há uma thread que irá
produzir dados e outra thread que irá realizar a retirada destes dados. O
problema que temos nesta situação se dá pela interação entre as duas threads,
pois neste processo, caso não seja empregado o método correto, pode ocorrer o
acesso a seção crítica pelas duas threads, o produtor poderá criar dados em
excesso, ou o consumidor poderá ficar em espera aguardando os dados a serem
produzidos.
Afim de, realizar a tarefa de criação de dados apenas quando houver espaço
em buffer e a retirada apenas quando houver dados disponíveis, foi desenvolvido
o seguinte algoritmo.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
5

#include <stdlib.h>
#include <process.h> // _beginthreadex() e _endthreadex()
#include <conio.h> // _getch
#define _CHECKERROR 1 // Ativa função CheckForError
#include "CheckForError.h"
//--------------------------------------------------------------------------------
// Casting para terceiro e sexto parâmetros da função _beginthreadex
typedef unsigned (WINAPI *CAST_FUNCTION)(LPVOID);
typedef unsigned *CAST_LPDWORD;

DWORD WINAPI Produtor(LPVOID); // declaração da função 1


DWORD WINAPI Consumidor(LPVOID); // declaração da função 2

int i,Max_Pos=20, Min_Pos=1;


HANDLE cheios;
HANDLE vazios;
int Buffer[20]; // Buffer circular
int InIndex = 0; // Índice para posição livre para inserção de dados
int OutIndex = 0; // Índice para posição ocupada contendo dado
LPLONG aux1,aux2;
int main()
{
HANDLE hThreads[2];
DWORD dwThreadId;
DWORD dwExitCode = 0;
DWORD dwRet;

cheios=CreateSemaphore(NULL,Min_Pos,Max_Pos,"EXCLUSAO");
vazios=CreateSemaphore(NULL,20,20,"EXCLUSAO");

hThreads[0] = (HANDLE) _beginthreadex( // criação da thread 1


NULL,
0,
(CAST_FUNCTION)Produtor, // casting necessário
(LPVOID)0,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[0]); // suspensão da thread até a mesma for requerida
CheckForError(hThreads[0]);
if (hThreads[0]) printf("Thread %d criada com Id= %0x \n\n", 0, dwThreadId);

hThreads[1] = (HANDLE) _beginthreadex( // criação da thread 2


NULL,
0,
6

(CAST_FUNCTION)Consumidor, // casting necessário


(LPVOID)1,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[1]); // suspensão da thread até a mesma for requerida

CheckForError(hThreads[1]);
if (hThreads[1]) printf("Thread %d criada com Id= %0x \n\n", 1, dwThreadId);

Sleep(2000);
ResumeThread(hThreads[1]);
ResumeThread(hThreads[0]);

dwRet = WaitForMultipleObjects(2,hThreads,TRUE,INFINITE);
CheckForError((dwRet >= WAIT_OBJECT_0) && (dwRet < WAIT_OBJECT_0 + 2));

for (i=0; i<2; ++i) {


GetExitCodeThread(hThreads[i], &dwExitCode);
printf("thread %d terminou: codigo=%d\n\n",i,dwExitCode);
CloseHandle(hThreads[i]); // apaga referência ao objeto
} // for
CloseHandle(cheios);
CloseHandle(vazios);

printf("\nAcione uma tecla para terminar\n");


_getch(); // // Pare aqui, caso não esteja executando no ambiente MDS

return EXIT_SUCCESS;
} // main

DWORD WINAPI Produtor(LPVOID index)


{
int k=10,Dado=0;
while(k>0){
WaitForSingleObject(vazios,INFINITE);
printf("\n\n Produzindo dados");
Dado=Dado+1;
Sleep(2000);
Buffer[InIndex] = Dado; // Insere dado no buffer
printf("\nfoi inserido o valor %d na posicao %d do buffer",Dado,InIndex);
InIndex = (InIndex + 1)%20; // Aponta próxima posição livre
ReleaseSemaphore(cheios,1,aux1); // Sinaliza Cheios
k--;
}
7

_endthreadex((DWORD) index);
return(0);
} // produtor

DWORD WINAPI Consumidor(LPVOID index)


{
int k=10,Dado=0;
while(k>0){
WaitForSingleObject(cheios,INFINITE);
printf("\n\nconsumindo dados");
Sleep(2000);
Dado = Buffer[OutIndex]; // Retira dado do buffer
printf("\nFoi retirado o valor %d da posicao %d do buffer",Dado,OutIndex);
Sleep(2000);
OutIndex = (OutIndex + 1)%20; // Aponta próxima posição ocupada
ReleaseSemaphore(vazios,1,aux2); // Sinaliza Vazios
k--;
} // end_loop
// ThreadT2
_endthreadex((DWORD) index);
return(0);
} // TestFunc1

Os dados criados pelo produtor são armazenados em um buffer de onde o


consumidor retira os dados, para isso foi declarado o int buffer que será os
“lugares”, onde os dados ocuparão.
Para que a thread produtora saiba o buffer vazio foi declarado o int InIndex,
que será como um ponteiro para informar a thread onde há espaços vazios no
buffer para armazenar mais um dado. Enquanto o int OutIndex funciona da
mesma forma, porém irá informar a thread consumidora o lugar onde será
retirado os dados.
Definindo a quantidade de lugares cheios e vazios criamos dois semáforos
respectivamente, para que possamos definir a quantidade de lugares cheios e
vazios e então apontá-los através o InIndex e OutIndex.
Então criamos as duas threads utilizando o beginthreadx, realizamos o check
de erro e através do DWORD WINAPI declaramos as threads, onde utilizamos o
while para acrescentar os dados e alterar o InIndex e na thread 2 para retirar os
dados e alterar o OutIndex.
8

Nesta programação não ocorre deaklock devido as duas threads não


acessam a seção crítica simultaneamente.

3.3 JANTAR DOS FILÓSOFOS

O enunciado deste problema segue a seguinte situação:

“Cinco filósofos estão sentados em torno de uma mesa circular, que tem em seu
centro um prato inesgotável de sushis (na história original era spaghetti, mas você
precisa de um único talher para comer spaghetti ou de dois talheres diferentes: um
garfo e uma colher). Sobre a mesa, entre cada dois filósofos está um talher japonês
(hashi). Cada filósofo para comer deve pegar dois talheres, uma vez que é difícil
equilibrar um sushi em um único talher. Cada filósofo realiza um loop infinito em
que pensa, toma os talheres um a um, come e devolve os talheres à mesa. As regras
a serem obedecidas são:
P1: Dois filósofos não podem segurar um mesmo talher simultaneamente.
P2: O filósofo só come, quando tem dois talheres
P3: Não deve haver deadlock, situação em que nenhum dos filósofos
consegue comer.
P4: Não pode haver inanição (neste caso inanição propriamente dita), isto é,
um filósofo querendo comer, deve eventualmente ter acesso aos dois talheres.
Eventualmente aqui significa: o evento (comer) ocorre com certeza, em algum
instante no futuro.”

Para resolver este problema empregamos o seguinte algoritmo:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>

char opcao;
int estado[5]={1,1,1,1,1}; // 1 pensado 2 com fome 3 comendo;

HANDLE Mutex;
HANDLE Semaforo[5];
HANDLE hThread[6];
void Pega_talheres(int i);
void Devolve_talheres(int i);
9

void Test(int i);

DWORD WINAPI Filosofo(LPVOID i);


DWORD WINAPI Menu(LPVOID);
//DWORD aux;
int main(int argc, char* argv[])
{
Mutex = CreateMutex(NULL,FALSE,"GerenciarTalher");

Semaforo[0] = CreateSemaphore(NULL,0,1,"Sem0");
Semaforo[1] = CreateSemaphore(NULL,0,1,"Sem1");
Semaforo[2] = CreateSemaphore(NULL,0,1,"Sem2");
Semaforo[3] = CreateSemaphore(NULL,0,1,"Sem3");
Semaforo[4] = CreateSemaphore(NULL,0,1,"Sem4");

for(int x=0;x<5;x++){
char *aux=(char*)x;
hThread[x] = CreateThread(NULL,0,Filosofo,aux,0,NULL);
if(hThread) printf("Thread %d criada com sucesso\n",x);
else
printf("ERRO na criacao da Thread %d\n",x);
}
hThread[5] = CreateThread(NULL,0,Menu,NULL,0,NULL);
if(hThread) printf("Thread Menu criada com sucesso\n");
else
printf("ERRO na criacao da Thread Menu\n");

do{
opcao = _getch();
if(opcao=='a')
estado[0]=2;
if(opcao=='b')
estado[1]=2;
if(opcao=='c')
estado[2]=2;
if(opcao=='d')
estado[3]=2;
if(opcao=='e')
estado[4]=2;
}while(opcao!='s');
10

WaitForMultipleObjects(5,hThread,TRUE,INFINITE);
for(int x=0;x<5;x++){
CloseHandle(hThread[x]);
CloseHandle(Semaforo[x]);
}
CloseHandle(hThread[5]);
CloseHandle(Mutex);
system("pause");
return 0;
}

DWORD WINAPI Filosofo(LPVOID i)


{
int x=(int)i;
do{
if(estado[x]==2){
Pega_talheres(x);
Sleep(rand()/3); // comendo...
Devolve_talheres(x);
}
Sleep(1000);
}while(opcao!='s');
ExitThread(0);
return 0;
}
DWORD WINAPI Menu(LPVOID){
do{
char *est;
Sleep(300);
system("cls");
printf("\n\nEstado dos filosofos\n\n");
for(int x=0;x<5;x++){
if(estado[x]==1) est="pensando";
if(estado[x]==2) est="com fome";
if(estado[x]==3) est="comendo...";
printf("Filosofo %d esta: %s\n",x,est);
}

}while(opcao!='s');
11

ExitThread(0);
return 0;
}

void Pega_talheres(int i)
{
WaitForSingleObject(Mutex,INFINITE);
Test(i);
ReleaseMutex(Mutex);
WaitForSingleObject(Semaforo[i],INFINITE);
}
void Devolve_talheres(int i)
{
int esquerda = (i+5-1)%5;
int direita = (i+1)%5;
WaitForSingleObject(Mutex,INFINITE);
estado[i]=1;
Test(esquerda);
Test(direita);
ReleaseMutex(Mutex);
}
void Test(int i)
{
int esquerda = (i+5-1)%5;
int direita = (i+1)%5;
if(estado[i]==2 && estado[esquerda]!=3 && estado[direita]!=3)
{
estado[i]=3;
ReleaseSemaphore(Semaforo[i],1,NULL);
}
}

Neste algoritmo garantimos que cada filósofo coma de forma organizada


para que ninguém fique sem comer ou que em nenhum momento não esteja
comendo.
Para isto iniciamos o programa declarando as nossas variáveis com as
quais iremos trabalhar para organizar este jantar. Em seguida declaramos as
funções com as quais iremos utilizá-las como uma metodologia para organizar
12

a seqüência que cada filósofo irá jantar, utilizando para isso um Mutex, cinco
semáforos, seis threads e outras três tarefas (pega talheres, devolve talheres
e test).
Sendo assim para realizar a organização da ação dos filósofos no jantar,
criamos duas threads uma que define o que ele deve fazer (Filosofo) e a outra
define o que ele está fazendo (Menu)
Tendo declarado as funções realizamos a criação das mesmas juntamente
com a inserção de um check de erro para certificar da criação das threads.
A partir de cada opção definimos o estado respectivo, utilizando a função
“do”.
Logo após declaramos o comportamento das threads criadas para definir
a ação de cada filósofo obedecendo os critérios definidos pelo enunciado do
problema, sendo que através dos estados e das ações realizadas pelos
filósofos conseguimos evitar que algum dos critérios solicitados fosse
desobedecidos.

3.4 SALÃO DE BARBEIRO

O enunciado deste problema segue a seguinte situação:

“Um salão de barbeiro tem uma cadeira de barbear, 5 cadeiras de espera, e um


barbeiro. Quando não há clientes, o barbeiro se senta na cadeira de barbear e
dorme. Um cliente chegando nesta situação é prontamente atendido. Se o
cliente chega e o barbeiro está ocupado, o cliente verifica o número de
cadeiras de espera livres. Se existir alguma livre, o cliente se senta e espera,
caso contrário, vai embora. Gerencie o salão de barbeiro usando semáforos.”

Empregamos o seguinte algoritmo para realizar esta tarefa:

#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "pthread.h"
#include "semaphore.h"

#define CHAIRS 5 /* número de cadeiras para os clientes à espera */


#define TRUE 1

sem_t customers; /* número de cliente à espera de atendimento */


sem_t barbers; /* número de barbeiros à espera de clientes */
sem_t mutex; /* para exclusão mútua */
13

int waiting = 0; /* clientes que estão esperando (não estão cortando) */

/* protótipos */
void* barber(void *arg);
void* customer(void *arg);
void cut_hair();
void customer_arrived();
void get_haircut();
void giveup_haircut();

int main() {
sem_init(&customers, TRUE, 0);
sem_init(&barbers, TRUE, 0);
sem_init(&mutex, TRUE, 1);

pthread_t b, c;

/* criando único barbeiro */


pthread_create(&b, NULL, (void *) barber, NULL);

/* criação indefinida de clientes */


while(TRUE) {
pthread_create(&c, NULL, (void *) customer, NULL);
sleep(1);
}

return 0;
}

void* barber(void *arg) {


while(TRUE) {
sem_wait(&customers); /* vai dormir se o número de clientes for 0 */
sem_wait(&mutex); /* obtém acesso a 'waiting' */
waiting = waiting - 1; /*descresce de um o contador de clientes à espera */
sem_post(&barbers); /* um barbeiro está agora pronto para cortar cabelo */
sem_post(&mutex); /* libera 'waiting' */
cut_hair(); /* corta o cabelo (fora da região crítica) */
}

pthread_exit(NULL);
}

void* customer(void *arg) {


sem_wait(&mutex); /* entra na região crítica */

if(waiting < CHAIRS) { /* se não houver cadeiras vazias, saia */


customer_arrived();
waiting = waiting + 1; /* incrementa o contador de clientes à espera */
sem_post(&customers); /* acorda o barbeiro se necessário */
sem_post(&mutex); /* libera o acesso a 'waiting' */
sem_wait(&barbers); /* vai dormir se o número de barbeiros livres for 0 */
get_haircut(); /* sentado e sendo servido */
} else {
sem_post(&mutex); /* a barbearia está cheia; não espera */
giveup_haircut();

pthread_exit(NULL);
14

void cut_hair() {
printf("Barbeiro estah cortando o cabelo de alguem!\n");
sleep(3);
}

void customer_arrived() {
printf("Cliente chegou para cortar cabelo!\n");
}
void get_haircut() {
printf("Cliente estah tendo o cabelo cortado!\n");
}

void giveup_haircut() {
printf("Cliente desistiu! (O salao estah muito cheio!)\n");
}
A solução aqui apresentada usa três semáforos: customers, que conta
os clientes á espera de atendimento (exceto o cliente que está na cadeira de
barbeiro, que não está esperando); barbers, o número de barbeiros (0 ou 1)
que estão ociosos à espera de clientes, e mutex, que é usado para exclusão
mútua.
Precisamos ainda de uma variável, waiting, que também conta os
clientes à espera de atendimento. É essencialmente uma cópia de customers.
A razão de se ter waiting é que não há uma maneira de ler o valor atual
do semáforo. Nessa solução, um cliente que entra na barbearia deve contar o
número de clientes à espera de atendimento. Se este for menor que o número
de cadeiras, ele ficará, do contrário, ele sairá.
Na solução, quando chega de manhã para trabalhar, o barbeiro
executa o método barber, que o leva a bloquear sobre o semáforo customers,
que inicialmente está em 0. O barbeiro então vai dormir, e permanece
dormindo até que o primeiro cliente apareça.
Quando chega, o cliente executa customers e inicia obtendo mutex
para entrar em uma região crítica. Se um outro cliente chega logo em
seguida, o segundo nada pode fazer até que o primeiro libere o mutex. O
cliente então verifica se o número de clientes à espera é menor que o número
de cadeiras. Se não for, ele liberará o mutex e sairá sem cortar o cabelo.
Se houver uma cadeira disponível, o cliente incrementará a variável
inteira waiting. Ele faz então um up no semáforo customers que acorda o
barbeiro. Nesse ponto, o barbeiro o pega, faz alguma limpeza e começa a
cortar o cabelo. Quando termina o corte de cabelo, o cliente sai do
15

procedimento e deixa a barbearia. Diferente de nossos exemplos anteriores,


não há um laço para o cliente porque para cada um deles terá apenas um
corte de cabelo. O barbeiro, contudo, contém um laço para tentar obter o
próximo cliente. Se houver algum outro cliente, um novo corte de cabelo será
iniciado. Do contrário, o barbeiro cairá no sono.
.
3.5 FUMANTES

O enunciado deste problema segue a seguinte situação:

“Um sistema possui 3 processos fumantes inveterados. Cada fumante prepara


cigarros e os fuma em um loop infinito. Para fumar um cigarro, três
ingredientes são necessários: papel, tabaco e fósforos. Um dos processos
fumantes tem tabaco, o outro papel e o outro fósforos. O agente tem um
suprimento infinito dos três ingredientes. O agente coloca dois dos
ingredientes escolhidos aleatoriamente sobre a mesa. O fumante que possui o
terceiro ingrediente pode então fumar o seu cigarro. Após fumar, este processo
sinaliza o agente que então escolhe dois novos ingredientes e o processo
continua. Resolva o problema usando semáforos. O processo fumante solicita
os recursos de que necessita e é atendido quando o recurso estiver disponível..”

Empregamos o seguinte algoritmo para realizar esta tarefa:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h> // _beginthreadex() e _endthreadex()
#include <conio.h> // _getch

#define _CHECKERROR 1 // Ativa função CheckForError


#include "CheckForError.h"

// Casting para terceiro e sexto parâmetros da função _beginthreadex


typedef unsigned (WINAPI *CAST_FUNCTION)(LPVOID);
typedef unsigned *CAST_LPDWORD;
DWORD WINAPI AgenteFornecedor(LPVOID); // declaração da função agente
DWORD WINAPI Fumante1(LPVOID); // declaração da função Fumante1
DWORD WINAPI Fumante2(LPVOID); // declaração da função Fumante2
DWORD WINAPI Fumante3(LPVOID); // declaração da função Fumante3

int i,op1=1,k=10;
HANDLE agente;
HANDLE S1;
HANDLE S2;
HANDLE S3;
HANDLE MUTEX;
LPLONG aux1,aux2,aux3,aux4,aux5,aux6,aux7;
int main()
16

{
HANDLE hThreads[4];
DWORD dwThreadId;
DWORD dwExitCode = 0;
DWORD dwRet;

agente=CreateSemaphore(NULL,1,1,"Agente");
S1=CreateSemaphore(NULL,0,1,"Semaphore_fumante1");
S2=CreateSemaphore(NULL,0,1,"Semaphore_fumante2");
S3=CreateSemaphore(NULL,0,1,"Semaphore_fumante3");
MUTEX=CreateMutex(NULL,FALSE,"EXCLUSAO");

hThreads[0] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)AgenteFornecedor, // casting necessário
(LPVOID)0,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[0]);

CheckForError(hThreads[0]);
if (hThreads[0]) printf("Thread %d criada com Id= %0x \n\n", 0, dwThreadId);

hThreads[1] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)Fumante1, // casting necessário
(LPVOID)1,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[1]);

CheckForError(hThreads[1]);
if (hThreads[1]) printf("Thread %d criada com Id= %0x \n\n", 1, dwThreadId);

hThreads[2] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)Fumante2, // casting necessário
(LPVOID)2,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[2]);

CheckForError(hThreads[2]);
if (hThreads[2]) printf("Thread %d criada com Id= %0x \n\n", 2, dwThreadId);

hThreads[3] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)Fumante3, // casting necessário
(LPVOID)3,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
17

SuspendThread(hThreads[3]);

CheckForError(hThreads[3]);
if (hThreads[3]) printf("Thread %d criada com Id= %0x \n\n", 3, dwThreadId);

Sleep(2000);

ResumeThread(hThreads[0]);
ResumeThread(hThreads[1]);
ResumeThread(hThreads[2]);
ResumeThread(hThreads[3]);

dwRet = WaitForMultipleObjects(4,hThreads,TRUE,INFINITE);
CheckForError((dwRet >= WAIT_OBJECT_0) && (dwRet < WAIT_OBJECT_0 + 2));

for (i=0; i<=3; ++i) {


GetExitCodeThread(hThreads[i], &dwExitCode);
printf("thread %d terminou: codigo=%d\n\n",i,dwExitCode);
CloseHandle(hThreads[i]); // apaga referência ao objeto

}
CloseHandle(agente);
CloseHandle(S1);
CloseHandle(S2);
CloseHandle(S3);
CloseHandle(MUTEX);

printf("\nAcione uma tecla para terminar\n");


_getch();

return EXIT_SUCCESS;
}

DWORD WINAPI AgenteFornecedor(LPVOID index)


{

while(k>0){
WaitForSingleObject(agente,INFINITE);
printf("\n\nAgente Fornecedor: \n1-papel e tabaco\n2-tabaco e fosforo\n3-fosforo e papel ");
scanf("%d",&op1);

if(op1==1){
ReleaseSemaphore(S1,1,aux1);

}
if(op1==2){
ReleaseSemaphore(S2,1,aux2);
}
if(op1==3){
ReleaseSemaphore(S3,1,aux3);
}
if((op1>3)||(op1<=0)){

printf("OPCAO INVALIDA\n");
ReleaseSemaphore(agente,1,aux7);
}
k--;
}
_endthreadex((DWORD) index);
return(0);
18

DWORD WINAPI Fumante1(LPVOID index)


{
while(k>0){
WaitForSingleObject(S1,INFINITE);
printf("\n O dono do fosforo da uma tragada...");
Sleep(3000);
ReleaseSemaphore(agente,1,aux4);
}
_endthreadex((DWORD) index);

return(0);
}

DWORD WINAPI Fumante2(LPVOID index)


{
while(k>0){
WaitForSingleObject(S2,INFINITE);
printf("\n O dono do papel da uma tragada...");
Sleep(3000);
ReleaseSemaphore(agente,1,aux5);
}
_endthreadex((DWORD) index);

return(0);
}

DWORD WINAPI Fumante3(LPVOID index)


{
while(k>0){
WaitForSingleObject(S3,INFINITE);
printf("\n O dono do tabaco da uma tragada...");
Sleep(3000);
ReleaseSemaphore(agente,1,aux6);
}
_endthreadex((DWORD) index);

return(0);
}

3.6 MONTANHA RUSSA

O enunciado deste problema segue a seguinte situação:

“Suponha que existam N processos do tipo passageiro e um processo do tipo


carro de montanha russa. Os passageiros esperam repetitivamente para dar
uma volta no carro que comporta C passageiro, C < N. Entretanto o carro só
começa o seu trajeto se todos os lugares estão ocupados. Use semáforos para
criar os protocolos de entrada e saída da seção crítica dos processos passageiro
e carro.”

Empregamos o seguinte algoritmo para realizar esta tarefa:


19

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h> // _beginthreadex() e _endthreadex()
#include <conio.h> // _getch
#define _CHECKERROR 1 // Ativa função CheckForError
#include "CheckForError.h"

// Casting para terceiro e sexto parâmetros da função _beginthreadex


typedef unsigned (WINAPI *CAST_FUNCTION)(LPVOID);
typedef unsigned *CAST_LPDWORD;

DWORD WINAPI PassageiroMontanhaRussa(LPVOID); // declaração da função 1


DWORD WINAPI CarroMontanhaRussa(LPVOID); // declaração da função 2

HANDLE passageiro;
HANDLE carro;
HANDLE MUTEX;
int sentado=0;
LPLONG aux1,aux2;
int main()
{
HANDLE hThreads[2];
DWORD dwThreadId;
DWORD dwExitCode = 0;
DWORD dwRet;

passageiro=CreateSemaphore(NULL,10,10,"Passageiro");
carro=CreateSemaphore(NULL,0,1,"Carro");
MUTEX=CreateMutex(NULL,FALSE,"EXCLUSAO");

hThreads[0] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)PassageiroMontanhaRussa, // casting necessário
(LPVOID)0,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[0]);

CheckForError(hThreads[0]);
if (hThreads[0]) printf("Thread %d criada com Id= %0x \n\n", 0, dwThreadId);

hThreads[1] = (HANDLE) _beginthreadex(


NULL,
0,
(CAST_FUNCTION)CarroMontanhaRussa, // casting necessário
(LPVOID)1,
0,
(CAST_LPDWORD)&dwThreadId // casting necessário
);
SuspendThread(hThreads[1]);

CheckForError(hThreads[1]);
if (hThreads[1]) printf("Thread %d criada com Id= %0x \n\n", 1, dwThreadId);

Sleep(2000);
20

ResumeThread(hThreads[1]);

ResumeThread(hThreads[0]);

dwRet = WaitForMultipleObjects(2,hThreads,TRUE,INFINITE);
CheckForError((dwRet >= WAIT_OBJECT_0) && (dwRet < WAIT_OBJECT_0 + 2));

int f=0;
for (f=0; f<2; ++f) {
GetExitCodeThread(hThreads[f], &dwExitCode);
printf("thread %d terminou: codigo=%d\n\n",f,dwExitCode);
CloseHandle(hThreads[f]); // apaga referência ao objeto

} // for
CloseHandle(carro);
CloseHandle(passageiro);
CloseHandle(MUTEX);

printf("\nAcione uma tecla para terminar\n");


_getch();
return EXIT_SUCCESS;
}

DWORD WINAPI CarroMontanhaRussa(LPVOID index)


{
int k=10,i=0;
while(k>0){

WaitForSingleObject(carro,INFINITE);
WaitForSingleObject(MUTEX,INFINITE);

printf("\n\n UOOOOOOOOOOOL.. Dando vooolta... UOL UOL UOL /o/ /o/ /o/ /o/ /o/ \n");
Sleep(2000);
for(i=0;i<10;i++){
ReleaseSemaphore(passageiro,1,aux1);
}
printf("\n THE END \n");
Sleep(1000);
ReleaseMutex(MUTEX);
k--;
}
_endthreadex((DWORD) index);

return(0);
}

DWORD WINAPI PassageiroMontanhaRussa(LPVOID index)


{
int k=100, p=0,cont=1;
while(k>0){

WaitForSingleObject(passageiro,INFINITE);
WaitForSingleObject(MUTEX,INFINITE);
printf("\n Passageiro %d entrou",cont);
cont++;
Sleep(500);

p=p+1;
if(p==5){
printf("\n Vamos Lá!");
21

ReleaseSemaphore(carro,1,aux2);
p=0;
Sleep(2000);
}
k--;
ReleaseMutex(MUTEX);
}

_endthreadex((DWORD) index);

return(0);
}
22

4. CONCLUSÃO

Podemos notar através deste trabalho que há diferentes maneiras de se chegar a


uma solução, que atenda as necessidades do usuário final do algoritmo.
O uso dos métodos e funções disponíveis para a programação concorrente se
tornam eficazes quando bem empregadas, levando em consideração o programa
como um todo e não apenas uma função específica.
As soluções utilizadas para evitar o acesso simultâneo a um recurso
compartilhado, (Mutex, Semáforos e seqüencias de programação) garante a
condição para a qual foram criadas, mas devemos levar em consideração os outros
efeitos de uma programação mau realizada que provocam deadlocks e inanição no
sistema.
Portanto existem demais formas de realizar a resolução destes problemas, mas
ter uma linha de raciocínio já definida, agiliza no processo de desenvolvimento de
outros programas.
23

5. REFERENCIAS BIBLIOGRAFICAS

 Livro: Programação Concorrente em Ambiente Windows. Constantino Seixas


Filho. Marcelo Szuster. Editora UFMG.

Vous aimerez peut-être aussi