Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added mp2.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion removefifo.bash
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
cd src/tmp
cd src2/tmp
rm fifoname
4 changes: 2 additions & 2 deletions run.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ echo "║ CHANGE FLAGS IN BASH ║"
echo "╚══════════════════════════╝"

cd src2/tmp
# rm *.* &
rm *.* &
cd ..

# $? = 0 se compilou bem
# $? = 2 otherwise
make -s
if [ $? -eq 0 ] ; then
./Q2 -t 5 fifoname & # Un <-t nsecs> fifoname
./Q2 -t 5 -l 4 -n 1 fifoname & # Un <-t nsecs> fifoname
P1=$!
./U2 -t 10 fifoname & # Qn <-t nsecs> [-l nplaces] [-n nthreads] fifoname
P2=$!
Expand Down
124 changes: 96 additions & 28 deletions src2/Q2.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,27 @@
#define ClearBit(A,k) ( A[(k/32)] &= ~(1 << (k%32)) )
#define TestBit(A,k) ( A[(k/32)] & (1 << (k%32)) )

double nsecs; /**< numbers of seconds the program will be running */
int nplaces; /**< size of array places */
int nThreadsActive; /**< nº of active threads at the moment*/

//com o intervalo entre pedidos 10 ms e valor maximo de uso 1000 ms, o valor maximo de lugares em uso
//ao mesmo tempo é 100. 100/32 =3.125 faz com que seja preciso tamanho 4
int places[4]; /**< array of bits to store used places */
int *places; /**< array of bits to store used places */
bit closed; /**< bit to store if Server is open or closed */


pthread_mutex_t mut=PTHREAD_MUTEX_INITIALIZER; /**< mutex to access places[] */
pthread_mutex_t mut2=PTHREAD_MUTEX_INITIALIZER; /**< mutex to enable closed bit */
pthread_mutex_t mut3=PTHREAD_MUTEX_INITIALIZER; /**< mutex to access nThreadsActive */


double nsecs; /**< numbers of seconds the program will be running */

void * thread_func(void *arg){
if(pthread_mutex_lock(&mut3)!=0){perror("Server-MutexLock");}
nThreadsActive++;
if(pthread_mutex_unlock(&mut3)!=0){perror("Server-MutexUnLock");}

char * request = (char *) arg; /**< Request string received from public fifo*/
int threadi, pid, dur, place; /**< Component of request*/
long tid; /**< thread id of client */
Expand All @@ -40,14 +50,14 @@ void * thread_func(void *arg){
printRegister(time(NULL), threadi, getpid(), pthread_self(), dur, -1, RECVD);

// make private fifo pathname
char privateFifo[BUFSIZE]="/tmp/";
char privateFifo[BUFSIZE]="tmp/";
char temp[BUFSIZE];
if(sprintf(temp,"%d",pid)<0){perror("Server-sprintf");}
strcat(privateFifo,temp);
strcat(privateFifo,".");
if(sprintf(temp,"%ld",tid)<0){perror("Server-sprintf");}
strcat(privateFifo,temp);

// open private fifo
int fd_priv; /**< private fifo file descriptor */
float startt = elapsedTime();
Expand Down Expand Up @@ -104,30 +114,82 @@ void * thread_func(void *arg){
// cleanup
ClearBit(places, place);
if(close(fd_priv)==-1){perror("Server-closePrivateFifo");}
if(pthread_mutex_lock(&mut3)!=0){perror("Server-MutexLock");}
nThreadsActive--;
if(pthread_mutex_unlock(&mut3)!=0){perror("Server-MutexUnLock");}
pthread_exit(NULL);
}

void argumentsReader(int argc, char* argv[], int *nplaces, int *nthreads, char fifoname[]){
/* 1 - ler valor de -t
* 2 - ler valor de -l
* 3 - ler valor de -n */
int flag = 0;
for (int i = 1; i < argc; i++)
{
if (flag == 1)
{
nsecs=atoi(argv[i])*1000;
flag = 0;
continue;
}
else if (flag == 2)
{
*nplaces = atoi(argv[i]);
flag = 0;
continue;
}
else if (flag == 3)
{
*nthreads = atoi(argv[i]);
flag = 0;
continue;
}
else if (strcmp(argv[i], "-t") == 0)
{
flag = 1;
continue;
}
else if (strcmp(argv[i], "-l") == 0)
{
flag = 2;
continue;
}
else if (strcmp(argv[i], "-n") == 0)
{
flag = 3;
continue;
}
else
strcpy(fifoname,argv[i]);
}
}

int main(int argc, char* argv[]) {
char fifoname[BUFSIZE]; /**< public fifo file name */
char fifopath[BUFSIZE]="/tmp/"; /**< public fifo path */
char fifopath[BUFSIZE]="tmp/"; /**< public fifo path */
char clientRequest[BUFSIZE]; /**< string read from public fifo */
pthread_t tid; /**< array to store thread id's */
closed.x=0; /**< 1-server closed | 0-server open */

// initialize available places at 0
for (int i = 0; i < 4; i++)
places[i] = 0;

nplaces = 0;
nThreadsActive = 0;
int nthreads=INT_MAX;
// check arguments
if (argc!=4) {
if (argc!=4 && argc!=6 && argc!=8){
printf("Usage: U1 <-t secs> fifoname\n");
exit(1);
}

//read arguments
strcpy(fifoname,argv[3]);
nsecs=atoi(argv[2])*1000;
argumentsReader(argc, argv, &nplaces, &nthreads, fifoname);
//printf("argc:%d\nargv:smth\nnsecs:%f\nnplaces:%d\nnthreads:%d\nfifoname:%s\n", argc, nsecs, nplaces, nthreads, fifoname);
strcat(fifopath,fifoname);
places = (int*) malloc(nplaces * sizeof(int));
int* places_copy = places;

// initialize available places at 0
for (int i = 0; i < nplaces; i++)
places[i] = 0;

//create public fifo
if(mkfifo(fifopath,0660)==-1){perror("Error creating public FIFO"); exit(1);}
Expand All @@ -144,29 +206,35 @@ int main(int argc, char* argv[]) {
// while loop to check public fifo
if(read(fd_pub,&clientRequest,BUFSIZE)<=0){ continue;}
// create thread with contents of public fifo
if(pthread_create(&tid, NULL, thread_func, &clientRequest)!=0){perror("Server-pthread_Create");}
if(pthread_detach(tid)!=0){perror("Server-pthread_detach");}
if (nThreadsActive < nthreads)
{
if(pthread_create(&tid, NULL, thread_func, &clientRequest)!=0){perror("Server-pthread_Create");}
if(pthread_detach(tid)!=0){perror("Server-pthread_detach");}
}
else
{
// o que é suposto fazer aqui?
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aqui acho que não precisamos deste else, ele simplesmente fica a correr este ciclo while para se manter aberto até acabar o tempo

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concordo, quando o if se tornar false fazer cleanup, por isso basta mudar para um while

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok estava a pensar e talvez tenha mesmo que ser um if na mesma, porque pode acontecer haver o máximo de threads ativas ao mesmo tempo (pouco provável acho, mas pode acontecer)

Copy link
Copy Markdown
Owner Author

@Ca-moes Ca-moes May 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Para chegar a esse else quer dizer que há um pedido mas não existem threads para o atender. Na thread do cliente este vai conseguir excrever no fifo público, fazer o fifo privado e abrir o fifo privado (porque tem NONBLOCK) . Quando tentar ler do fifo é que irá dar erro devido a esta parte :

// Attempts to read from private fifo until there's a response
  int try = 0;
  while(tmpresult<=0 && try < 5){
    if (try != 0)
      usleep(100*1000);    
    tmpresult = read(fd_priv,&receivedMessage,BUFSIZE);
    try++;
  }
  if(tmpresult<=0) {
    printRegister(time(NULL), threadn, getpid(), pthread_self(), useTime, -1, FAILD);

    if(close(fd_priv)==-1){perror("Client-closePrivateFifo");}
    if (unlink(privateFifo)==-1){perror("Error destroying private fifo:");}
    pthread_exit(0);
  }

Que acho que é a estratégia que faz sentido. Tendo em conta que é uma casa de banho, se for feito um pedido e não houver ninguém para "atender" o cliente tem de tentar mais x vezes e voltar mais tarde.
E.G. Se a casa de banho de S.Bento não tivesse torniquete, só a senhora a verificar as senhas. Se chegar lá um gajo que quer mandar o Obama à casa branca e não tiver lá a senhora ele fica um tempo à espera e depois vai embora, para retornar mais tarde ou ir a outro sitio.

Outra estratégia seria guardar o pedido numa fila para assim que houver o thread disponivel tratar desse pedido, mas a fila já está meio implícita nas tentativas que a thread client faz.

Mais 2 coisas:
image

cada pedido é atendido por um thread, que comunica com o thread cliente e controla o tempo de utilização de um lugar do Quarto de Banho; se não houver lugares disponíveis, espera que haja e prossegue;

Este se não houver lugares diponiveis é dentro de cada thread que se vai verificar, não engloba este problema.


image

as mensagens trocadas são sempre aos pares:
○ cada pedido terá sempre uma resposta

Vi isto no enunciado e acho que estamos meio lixados. Da forma que está agora como está a fazer a verificação no read por tentativas não está garantido que terá sempre uma resposta. Da forma que está agora serve para caso haja algum erro (de escrita ou leitura dos fifos) que não cause o término do programa de forma inesperada, mas não assegura esta condição :/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isso quer dizer que o nthreads é o nthreads em simultâneo? E o cliente tem de esperar que hajam threads disponiveis para o atender? Damn

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nthreads – nº (máximo) de threads a atender pedidos

Yep, em simultâneo não pode haver mais do que nthreads ativas

Quanto ao cliente é que não tenho a certeza. Acho que o objetivo é ter o servidor a tratar de mais trabalho em vez de pôr o cliente a pensar quando pode fazer pedidos ou não.
Acho que o cliente apenas faz pedidos e não se interessa se existem threads para o atender ou não, se houver -> fixe, pedido atendido, se não houver -> FAILD . Acho que não há problema com a parte do "se não houver" porque estão a ser feitos "pedidos" e não "clientes" novos

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pois faz sentido, os pedidos podem ser da mesma pessoa, o cliente nao tem de saber quando fazer o pedido, simplesmente faz e pronto depois vê se consegue ser atendido ou não, acho q ta bem assim

}

}

// closing sequence
if(unlink(fifopath)==-1){perror("Error destroying public fifo:");}
if(pthread_mutex_lock(&mut2)!=0){perror("Server-MutexLock");}
closed.x = 1;
if(pthread_mutex_unlock(&mut2)!=0){perror("Server-MutexUnLock");}
float starttime;
int readreturn;

// notifies client threads that server is closed
starttime = elapsedTime();
do{
readreturn = read(fd_pub, &clientRequest, BUFSIZE);
} while (readreturn == 0 && elapsedTime() - starttime < MSATTEMPT);
if (readreturn > 0){
if(pthread_create(&tid, NULL, thread_func, &clientRequest)!=0){perror("Server-pthread_Create");}
if(pthread_detach(tid)!=0){perror("Server-pthread_detach");}
//float starttime;
int readreturn = read(fd_pub, &clientRequest, BUFSIZE);
while (readreturn != 0)
{
printf("Dentro de while\n");
if(readreturn <0 ){perror("Server-read error");}
if(pthread_create(&tid, NULL, thread_func, &clientRequest)!=0){perror("Server-pthread_Create");}
if(pthread_detach(tid)!=0){perror("Server-pthread_detach");}
readreturn = read(fd_pub, &clientRequest, BUFSIZE);
}

// cleanup
if(close(fd_pub)==-1){perror("Server-closePublicFifo");}
if(unlink(fifopath)==-1){perror("Error destroying public fifo:");}
free(places_copy);
pthread_exit((void*)0);
}
46 changes: 32 additions & 14 deletions src2/U2.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ pthread_mutex_t mut2=PTHREAD_MUTEX_INITIALIZER; /**< mutex para aceder a i*/
*/
void * thread_func(void *arg){
// updating i with mutex's
int threadn;/**< thread number */
if(pthread_mutex_lock(&mut2)!=0){perror("Client-MutexLock");}
i++;
threadn = i++;
if(pthread_mutex_unlock(&mut2)!=0){perror("Client-MutexUnLock");}

int fd_pub; /**< file descriptor of public fifo */
Expand All @@ -44,28 +45,34 @@ void * thread_func(void *arg){

// opening Public fifo to be able to write
float startt = elapsedTime();
int attempt = 0;
do{
fd_pub = open(fifopath,O_WRONLY);
} while (fd_pub==-1 && elapsedTime() - startt < MSATTEMPT);
if (fd_pub < 0) {
fprintf(stderr, "%d-%s\n", i, "Client - Error Opening Public Fifo");
fd_pub = open(fifopath,O_WRONLY, O_NONBLOCK);
attempt++;
} while (fd_pub==-1 && attempt < 5);
if (fd_pub == -1) {
printRegister(time(NULL), threadn, getpid(), pthread_self(), useTime, -1, CLOSD);

if(pthread_mutex_lock(&mut)!=0){perror("Client-MutexLock");}
serverOpen.x = 0;
if(pthread_mutex_unlock(&mut)!=0){perror("Client-MutexUnLock");}
pthread_exit(NULL);
}

// Making of message to send, writing of message and closing of fifo
if(sprintf(request,"[ %d, %d, %lu, %d, -1 ]", i, getpid(), pthread_self(), useTime)<0){perror("Client-sprintf");}
if(sprintf(request,"[ %d, %d, %lu, %d, -1 ]", threadn, getpid(), pthread_self(), useTime)<0){perror("Client-sprintf");}

if (write(fd_pub, &request, BUFSIZE)<0){
perror("Error writing request: ");
if(close(fd_pub)==-1){perror("Client-closePublicFifo");}
pthread_exit(NULL);
}

printRegister(time(NULL), i, getpid(), pthread_self(), useTime, -1, IWANT);
printRegister(time(NULL), threadn, getpid(), pthread_self(), useTime, -1, IWANT);
if(close(fd_pub)==-1){perror("Client-closePublicFifo");}

// Making of pathname of private fifo
char privateFifo[BUFSIZE]="/tmp/";
char privateFifo[BUFSIZE]="tmp/";
char temp[BUFSIZE];
if(sprintf(temp,"%d",(int)getpid())<0){perror("Client-sprintf");}
strcat(privateFifo,temp);
Expand All @@ -80,11 +87,10 @@ void * thread_func(void *arg){
int fd_priv;
startt = elapsedTime();
do{
fd_priv = open(privateFifo, O_RDONLY);
fd_priv = open(privateFifo, O_RDONLY | O_NONBLOCK);
} while (fd_priv==-1 && elapsedTime() - startt < MSATTEMPT);

if (fd_priv < 0) {
if(fprintf(stderr, "%d.%s\n", i, "Client - Error Opening Private Fifo")<0){perror("Client-fprintf");}
if(fprintf(stderr, "%d.%s\n", threadn, "Client - Error Opening Private Fifo")<0){perror("Client-fprintf");}
if(close(fd_priv)==-1){perror("Client-closePrivateFifo");}
pthread_exit(NULL);
}
Expand All @@ -94,8 +100,20 @@ void * thread_func(void *arg){
int tmpresult = read(fd_priv,&receivedMessage,BUFSIZE);

// Attempts to read from private fifo until there's a response
while(tmpresult==0){tmpresult = read(fd_priv,&receivedMessage,BUFSIZE);}
if(tmpresult<0) {printRegister(time(NULL), i, getpid(), pthread_self(), useTime, -1, FAILD);}
int try = 0;
while(tmpresult<=0 && try < 5){
if (try != 0)
usleep(100*1000);
tmpresult = read(fd_priv,&receivedMessage,BUFSIZE);
try++;
}
if(tmpresult<=0) {
printRegister(time(NULL), threadn, getpid(), pthread_self(), useTime, -1, FAILD);

if(close(fd_priv)==-1){perror("Client-closePrivateFifo");}
if (unlink(privateFifo)==-1){perror("Error destroying private fifo:");}
pthread_exit(0);
}

// If there's a response, parse the response to different variables
int threadi, pid, dur, place;
Expand All @@ -120,7 +138,7 @@ void * thread_func(void *arg){

int main(int argc, char* argv[], char *envp[]) {
char fifoname[BUFSIZE]; /**< public fifo file name */
char fifopath[BUFSIZE]="/tmp/"; /**< public fifo path */
char fifopath[BUFSIZE]="tmp/"; /**< public fifo path */
double nsecs; /**< numbers of seconds the program will be running */
pthread_t tid; /**< array to store thread id's */
serverOpen.x = 1;
Expand Down