Jump to content

Ajuda Pthread e Mutex


besty
 Share

Recommended Posts

Boas.

Estou a tentar resolver um problema em C, que consiste na sincronização, apenas por mutex, de um escritor e de um leitor.

O problema tem 3 restrições:

- Não pode haver escritores diferentes a correr simultaneamente.

- Não pode haver escritores e leitores a correr simultaneamente.

- Pode haver leitores a correr simultaneamente.

Vou dar um exemplo( o programa deveria imprimir uma sequência deste género ) :

(W=escritor, R=leitor)

W0: Start

W0: End

W1: Start

W1: End

R0: Start

R1: Start

R0: End

R2: Start

R1: End

R2: End

W2: Start

W2: End

Já andei às voltas com isto e não consigo por a funcionar como devia ser. Tirei duvidas com o professor e ele mande um mail com algumas pistas.

You will need at least two locks. You should count the number of threads that are simultaneously reading and allow only the first thread of the batch to lock out the writers and the last one to finish the read to unlock them.

Mesmo assim não estou a conseguir resolver a segunda restrição, que é onde o programa me está a dar problemas. Provavelmente ainda não percebi muito bem a lógica dos mutex.

O código que consegui até agora é o seguinte:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> 

#define N 3

/*Declaration*/
void *writer(int n);
void *reader(int n);
void clean();

/*Init*/

pthread_mutex_t mutex,mutex1;

int main(int argc, char **argv)
{
int i;
pthread_t thrR[N];
pthread_t thrW[N];

pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex1,NULL);


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

	pthread_create(&thrW[i],NULL,writer, (void *)i);
	pthread_create(&thrR[i],NULL,reader, (void *)i);
}

for(i=0;i<N;++i){
	pthread_join(thrW[i], NULL);
	pthread_join(thrR[i], NULL);
}

/*Clean Resources*/
clean();

return 0;
}

void *writer(int n){
int i;

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

	pthread_mutex_lock(&mutex);

	printf("W%d:S \n",n);
	sleep(2*n);
	printf("W%d:E \n",n);

	pthread_mutex_unlock(&mutex);

}

return NULL;
}

void *reader(int n){
int i=0;

if (n==0) pthread_mutex_unlock(&mutex);


         while(i<5){

                printf("R%d:S \n",n);
		pthread_mutex_lock(&mutex1);

		sleep(n);

		pthread_mutex_unlock(&mutex1);
		printf("R%d:E \n",n);
		i++;
}			

        if (n==n) pthread_mutex_lock(&mutex);

        return NULL;
}

void clean()
{
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex1);
}

Agradecia mesmo uma ajuda. Já estou a dar em doido com isto.

Link to comment
Share on other sites

Eh pá...

É fim de semana e tal... estive a rever o que sabia de mutexes e threads e assim de repente não terás de bloquear o mutex1 no escritor para garantir que nenhum leitor corre enquanto o escritor está a correr?

Ou então, e seguindo o que o professor disse, a primeira thread leitora deve bloquear o mutex do escritor e a última deve desbloquear esse mutex permitindo então ao escritor continuar. 

Também reparei que da maneira que escreveste o escritor, nunca terás mais que um a correr ao mesmo tempo, que é uma das condicões do enunciado.

Sinceramente não consigo dar-te mais ajuda sem meter mãos à obra (coisa que por enquanto não posso).

tenta também ver os atributos de mutexes... talvez consigas algo daí. :\

Abraco e parabéns por esbocares a solucão antes de pedires ajuda.

http://www.cs.cf.ac.uk/Dave/C/node31.html#SECTION003111000000000000000

include <ai se te avio>

Mãe () {

}

Link to comment
Share on other sites

Estive a pensar um pouco mais no problema... alterei o teu código e tudo... mas antes de o colocar online pensei em várias coisas...

Primeiro no teor das minhas queixas no fórum... tenho-me queixado imenso sobre pedirem trabalhos de casa no fórum e apesar de saber que não estás no primeiro ano da faculdade, sei por experiência própria que é possível ser-nos pedido código com mutexes e threads sem saberes muito bem programar em C. Aconteceu-me a mim e embora sabendo que o meu percurso não foi propriamente normal, é possível.

Segundo, pensei também um pouco por causa do motivo acima explicado, que a minha solucão, sem a testar, iria estar errada ou com erros no que toca ao comportamento thread safe do meu código.

Daí que não vou deixar código nenhum, mas vou-te dar uma dica para a resolucão do problema.

Da forma que escreveste o teu código o leitor 0 vais desbloquear o mutex escritor permitindo assim que ambos corram ao mesmo tempo e no fim, todos os leitores bloqueiam o escritor... outra coisa que também está errada é que cada leitor bloqueia o mutex leitor, não permitindo assim que existam mais que um escritor em cada momento, invalidando a 3 condicão.

A minha solucão passa por: 

Teres um mutex que guarda uma variável global com o número de threads leitoras em execucão. Sempre que uma thread leitora comeca, essa variável é incrementada. Quando a thread terminar, a variável é decrementada.

Depois na thread leitora, antes de tentares bloquear o mutex escritor, vês se existem mais threads leitoras. Se não existirem, bloqueias o escritor e fazes o que tens a fazer. Ao sair, se essa thread for a última, desbloqueia o escritor. As threads que não forem a primeira ou a última podem fazer o que querem e estão livres de testar mutexes.

Tás a ver a ideia?

Agora a minha sequência de passos está, no minimo, errada... tenho a certeza que existem problemas na sequência de bloqueio no mutex de leitura, mas pelo menos já tens uma ideia de onde comecar.

Modificado para adicionar que a minha solução funciona. 🙂 Será que o MJ me altera a nota da cadeira onde me vi à rasca para fazer isto? LOL

include <ai se te avio>

Mãe () {

}

Link to comment
Share on other sites

Eu percebo completamente a tua posição e compreendo a tua definição de ajuda em relação à programação. Recorri mais a este tipo de ajuda, porque estou em erasmus na Eslovenia e os professores simplesmente dão-te uma folha com o problema e fazem aquela cara de "desamerdate". E óbvio que não quero roubar tempo a ninguém e agradeço imenso estares a a perde-lo comigo.

Esqueci-me de dizer um pormenor importante. No enunciado apenas me dizem as restrições e dois templates para a função writer e reader:

void *writer(int n){
int i;

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

	printf("W%d:S \n",n);
	sleep(2*n);
	printf("W%d:E \n",n);
}

}

void *reader(int n){
int i=0;

while(i<5){

            printf("R%d:S \n",n);
    sleep(n);
    printf("R%d:E \n",n);
    i++;
         }

}

Em relação à tua solução tenho uma dúvida, ou então n percebi o que querias dizer. Qual é a razão de incrementar a variável para saber em thread de leitura estamos para depois ao fim a a decrementar, assim não vou conseguir comparar com o número efectivo de threads?

De qualquer das maneiras com a tua ajuda e de outro user de um outro forum. cheguei a uma solução. Não sei se é que o professor vai querer, mas pelo menos as restrições estão lá.

Alterei tb o argumento a ser enviado para função(n). Porque ao enviar 0 o sleep não fazia sentido nenhum.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> 

#define N 2

/*Declaration*/
void *writer(int n);
void *reader(int n);
void clean();
unsigned int count=0;

/*Init*/

pthread_mutex_t mutex,mutex1;

int main(int argc, char **argv)
{
int i;
int n[N];
pthread_t thrR[N];
pthread_t thrW[N];

pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex1,NULL);


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

	n[i]=i+1;
	pthread_create(&thrW[i],NULL,writer, (void *)n[i]);
	pthread_create(&thrR[i],NULL,reader, (void *)n[i]);
}

for(i=0;i<N;++i){
	pthread_join(thrW[i], NULL);
	pthread_join(thrR[i], NULL);
}

/*Clean Resources*/
clean();

return 0;
}

void *writer(int n){
int i;

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

	pthread_mutex_lock(&mutex);

	printf("W%d:S \n",n);
	sleep(2*n);
	printf("W%d:E \n",n);

	pthread_mutex_unlock(&mutex);

}

return NULL;
}

void *reader(int n){
int i=0;	


pthread_mutex_lock(&mutex1);

count++;

if (count==1) {
	pthread_mutex_lock(&mutex);

}

pthread_mutex_unlock(&mutex1);

while(i<5){

	printf("R%d:S \n",n);
	pthread_mutex_lock(&mutex1);

	sleep(n);

	printf("R%d:E \n",n);
	pthread_mutex_unlock(&mutex1);

	i++;
}			

if (count==N) {
	count=0;
	pthread_mutex_unlock(&mutex);
}

return NULL;
}

void clean()
{
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex1);
}

Com duas threads, a solução deu:

W1:S

W1:E

R1:S

R2:S

R1:E

R1:S

R2:E

R2:S

R1:E

R1:S

R2:E

R2:S

R1:E

R1:S

R2:E

R2:S

R1:E

R1:S

R2:E

R2:S

R1:E

R2:E

W2:S

W2:E

W1:S

W1:E

W2:S

W2:E

W1:S

W1:E

W2:S

W2:E

W1:S

W1:E

W2:S

W2:E

W1:S

W1:E

W2:S

W2:E

Está a funcionar, mas não muito aleatoriamente. Se a solução que tu implementas-te tem melhores resultados, agradecia mais umas dicas. 🙂

Link to comment
Share on other sites

Recorri mais a este tipo de ajuda, porque estou em erasmus na Eslovenia e os professores simplesmente dão-te uma folha com o problema e fazem aquela cara de "desamerdate".

Bem vindo à vida de engenheiro. 🙂

Uma das coisas que vais precisar para a tua vida é mesmo este "dom" do desemerdanço. lol

Agora adiante, o teu código ainda não faz o que é pedido no enunciado. Na função reader() tu excluis todas as threads leitoras de funcionarem em simultâneo porque bloqueias o mutex leitor no inicio e desbloqueias no fim. Logo os leitores correm de vez em vez.

Tens de bloquear o mutex, incrementar o número de threads leitoras, desbloquear o mutex, fazer o código que pretendes, bloquear o mutex, decrementar e desbloquear. Assim garantes liberdade às threads leitoras de executarem o seu código. O sleep ajuda a mostrar isto dos leitores a funcionar em simultâneo.

Saberes o número de threads leitoras permite-te bloquear o escritor enquanto as threads leitoras estão a funcionar. Se uma thread leitora começar enquanto outra já está a correr, ela pode fazer o seu trabalho e continuar a bloquear o escritor.

@asworm

Como já referi eu não sou a maior autoridade mundial em threads, mutexes e semáforos. No entanto, pode este exercício introduzir o conceito de semáforo. Não sei, não foi especificado.

include <ai se te avio>

Mãe () {

}

Link to comment
Share on other sites

Boas... este código foi projectado para windows ou linux?

é que eu definitivamente não estou a perceber nada deste código... eu quando aprendi a trabalhar com mutex, falavam-me em semáforos

sem_up(); incrementava o valor do semáforo

sem_down(); decrementava o valor do semáforo

Um mutex é um semáforo binário.

Link to comment
Share on other sites

Tens de bloquear o mutex, incrementar o número de threads leitoras, desbloquear o mutex, fazer o código que pretendes, bloquear o mutex, decrementar e desbloquear. Assim garantes liberdade às threads leitoras de executarem o seu código. O sleep ajuda a mostrar isto dos leitores a funcionar em simultâneo.

O mutex que estás a falar é o dos leitores, certo?

pthread_mutex_lock(&mutex1);
        
        count++;
        
        if (count==1) {
                pthread_mutex_lock(&mutex);
                
        }

        pthread_mutex_unlock(&mutex1);

Mas a primeira parte não é como estou a fazer. Faço lock ,incremento e unlock.

Agora a segunda parte que falas em decrementar é que não estou mesmo a ver o sentido. Estou um bocado à nora com isto.

🙂

Link to comment
Share on other sites

Um mutex é um semáforo binário.

eu sei... o problema é que eu uso um ficheiro semaforos.c e estão lá implementadas as funções sem_up, sem_down...

EDIT: OK cheguei agora as threads não fazia ideia que as threads têm os seus próprios mutex.

Got it?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.