[ Foro de C ]

Problema con problema de concurrecia de procesos

14-Mar-2025 12:38
Invitado (Nacho)
0 Respuestas

Estoy realizando un proyecto universitario.
Es un sistema de votación multiproceso.
El proceso principal debe crear el número indicado de procesos y enviar una
señal para que elijan a un candidato.
Este candidato enviará una señal para que los demás procesos comiencen a votar.
Los procesos votan a través de un archivo compartido.
El proceso candidato contará los votos y determinará si ha ganado.
Después, enviará de nuevo la señal de selección de candidato para iniciar una
nueva ronda.
El programa puede finalizarse con una interrupción de teclado o una alarma.

Este es mi código:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

#define MAX_PROCES 500
#define FILE_PIDS "PIDS.txt"
#define FILE_VOTANTE "votante.txt"
#define SEM_CANDIDATO "/candidato"
#define SEM_VOTACION "/votacion"
#define SEM_CONTADOR "/contador"
#define SEM_EMPEZAR_VOTACION "/empezar_votacion"


int N_PROCS;

int list[MAX_PROCES];
pid_t pid_candidato=-1;
int empezar_votacion=0;


FILE *f_pids,*f_votante;

sem_t *sem_candidato;  
sem_t *sem_archivo;
sem_t *sem_contador;


void print_signal_mask(sigset_t *mask) {
   int signals[] = {SIGUSR1, SIGUSR2, SIGINT, SIGTERM, SIGALRM};
   const char *signal_names[] = {"SIGUSR1", "SIGUSR2", "SIGINT", "SIGTERM", "SIGALRM"};

   printf("Máscara de señales activa: [ ");
   for (int i = 0; i < sizeof(signals) / sizeof(signals[0]); i++) {
       if (sigismember(mask, signals[i])) {
           printf("%s ", signal_names[i]);
       }
   }
   printf("]\n");
}


void votante(){

   int voto,comprobacion;
   sigset_t sig_mask, old_mask;



   sigemptyset(&sig_mask);
   sigaddset(&sig_mask, SIGUSR1);  
   sigprocmask(SIG_BLOCK, &sig_mask, &old_mask);

   
   
   sem_wait(sem_archivo);

   

   

   f_votante = fopen(FILE_VOTANTE, "a");
   if (f_votante == NULL) {
       f_votante=fopen(FILE_VOTANTE, "w");

       if(f_votante==NULL){
           perror("fopen");
           exit(EXIT_FAILURE);
       }
 
   }

   srand(time(NULL)+getpid());

   voto = rand() % 2;
   

   comprobacion= fprintf(f_votante, "%c\n", voto ? 'Y' : 'N');

   if(comprobacion<0){
       perror("fprintf");
       exit(EXIT_FAILURE);
   }
   

   sem_post(sem_contador);


   fclose(f_votante);

   sem_post(sem_archivo);

   

   sigprocmask(SIG_SETMASK, &old_mask, &sig_mask);




   
   

   sigsuspend(&old_mask);

   

   


}


void candidato(){

   int i,votos_si=0,votos_no=0,valor=0;
   char voto;


   sigset_t sig_mask, old_mask;

   


   

   printf("Candidato %d => [",getpid());

   pid_candidato=getpid();

   sigemptyset(&sig_mask);
   sigaddset(&sig_mask, SIGUSR1);  
   sigprocmask(SIG_BLOCK, &sig_mask, &old_mask);


   for(i=0;i<N_PROCS;i++){
       usleep(1);
       kill(list[i], SIGUSR2);
       
   }

   
   

   while (1) {

   


       if(sem_getvalue(sem_contador,&valor)==-1){
           perror("sem_getvalue");
           exit(EXIT_FAILURE);
       }
       if(valor==N_PROCS){
           break;
       }
       else{
           usleep(1000);
       }

   }


   while (valor > 0) {
   sem_trywait(sem_contador);
   sem_getvalue(sem_contador, &valor);

   }

   

   votos_si = 0;
   votos_no = 0;

   f_votante=fopen(FILE_VOTANTE,"r");
   if(f_votante==NULL){
       perror("fopen");
       exit(EXIT_FAILURE);
   }

   while(fscanf(f_votante,"%c",&voto)==1){
       if(voto=='Y'){
           printf(" Y ");
           votos_si++;
       }
       if(voto=='N'){

           printf(" N ");

           votos_no++;
           
       }
           
   }


   fclose(f_votante);

   printf("] =>");

   if(votos_si>votos_no){
       
       printf("Aceptado\n");
   }

   else{

       printf("Rechazado\n");
   }


   unlink(FILE_VOTANTE);
 

   sigprocmask(SIG_SETMASK, &old_mask, NULL);

   usleep(25000);

   sem_post(sem_candidato);

   for (i = 0; i < N_PROCS; i++) {
           kill(list[i], SIGUSR1);
   }

   sigsuspend(&old_mask);

   }




void handler_SIGINT(int sig) {
   int i = 0;


   for (i = 0; i < N_PROCS; i++) {
       kill(list[i], SIGTERM);
   }
   for (i = 0; i < N_PROCS; i++) {
       wait(NULL);
   }

   sem_close(sem_archivo);

   sem_close(sem_candidato);

   sem_close(sem_contador);


   sem_unlink(SEM_CANDIDATO);
   sem_unlink(SEM_VOTACION);
   sem_unlink(SEM_CONTADOR);



   printf("\nFinishing by signal\n");
   exit(EXIT_SUCCESS);
}


void handler_SIGALRM(int sig) {

   int i;

   

   for(i=0;i<N_PROCS;i++){
       kill(list[i], SIGTERM);
   }

   for (int i = 0; i < N_PROCS; i++) {
       wait(NULL);
   }

   printf("Finish by alarm\n");

   sem_close(sem_archivo);

   sem_close(sem_candidato);

   sem_close(sem_contador);

   sem_unlink(SEM_CANDIDATO);
   sem_unlink(SEM_VOTACION);
   sem_unlink(SEM_CONTADOR);



   exit(EXIT_SUCCESS);


}


void handler_SIGTERM(int sig) {
   exit(0);
}

void handler_SIGUSR1(int sig) {

   

   sem_wait(sem_candidato);

   


   candidato();


   

   


   
}

void handler_SIGUSR2(int sig) {



   


   if(getpid()!=pid_candidato){


        votante();
       
   }
   

 
   
   
}




int main(int argc, char *argv[]){

   int N_SECS,i;
   pid_t pid;

   struct sigaction act, act1, act2, act3,act4;
   
   sigset_t sig_mask, old_mask,sig_mask1,old_mask1;

   sem_unlink(SEM_CANDIDATO);
   sem_unlink(SEM_VOTACION);
   sem_unlink(SEM_CONTADOR);
   

   sigemptyset(&sig_mask);
   sigaddset(&sig_mask, SIGALRM);  
   sigprocmask(SIG_BLOCK, &sig_mask, &old_mask);

   sigemptyset(&sig_mask1);
   sigaddset(&sig_mask1, SIGUSR1);
   sigaddset(&sig_mask1, SIGUSR2);  
   sigprocmask(SIG_BLOCK, &sig_mask1, &old_mask1);

 


   if(argc != 3){

       fprintf(stderr, "Usage: %s <N_PROCS> <N_SECS>\n", argv[0]);
       exit(EXIT_FAILURE);

   }

   N_PROCS = atoi(argv[1]);

   N_SECS=atoi(argv[2]);

   if(N_PROCS > MAX_PROCES){
       fprintf(stderr, "The maximum number of processes is %d\n", MAX_PROCES);
       exit(EXIT_FAILURE);
   }


   act1.sa_handler = handler_SIGUSR1;
   sigemptyset(&(act1.sa_mask));
   act1.sa_flags = 0;
   act2.sa_handler = handler_SIGTERM;
   sigemptyset(&(act2.sa_mask));
   act2.sa_flags = 0;
   act3.sa_handler = handler_SIGUSR2;
   sigemptyset(&(act3.sa_mask));
   act3.sa_flags = 0;

   


   


   if ((sem_candidato = sem_open(SEM_CANDIDATO, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1 )) ==
     SEM_FAILED) {
   perror("sem_open");
   exit(EXIT_FAILURE);
   }

   if ((sem_archivo = sem_open(SEM_VOTACION ,O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) ==
     SEM_FAILED) {
   perror("sem_open");
   exit(EXIT_FAILURE);
     }

   if ((sem_contador = sem_open(SEM_CONTADOR, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0)) ==
     SEM_FAILED) {
   perror("sem_open");
   exit(EXIT_FAILURE);
   }



   if ( sigaction(SIGUSR1, &act1, NULL) < 0 || sigaction(SIGTERM, &act2, NULL) < 0 || sigaction(SIGUSR2, &act3, NULL) < 0) {
       perror("sigaction");
       exit(EXIT_FAILURE);
   }

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

       pid=fork();

       if(pid<0){
           perror("fork");
           exit(EXIT_FAILURE);
       }

       if(pid==0){
           sigprocmask(SIG_SETMASK, &old_mask1, NULL);

           sigsuspend(&old_mask1);
       }

       else{
           list[i]=pid;
       }

   }

   act.sa_handler = handler_SIGINT;
   sigemptyset(&(act.sa_mask));
   act.sa_flags = 0;
   if (sigaction(SIGINT, &act, NULL) < 0) {
       perror("sigaction");
       exit(EXIT_FAILURE);
   }

   act4.sa_handler = handler_SIGALRM;
   sigemptyset(&(act4.sa_mask));
   act4.sa_flags = 0;

   if (sigaction(SIGALRM, &act4, NULL) < 0) {
       perror("sigaction");
       exit(EXIT_FAILURE);
   }

   

   


   f_pids=fopen(FILE_PIDS,"w");

   if(!f_pids){
       perror("fopen");
       exit(EXIT_FAILURE);
   }

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

       if(fprintf(f_pids,"%d\n",list[i])<0){
           perror("fprintf");
           exit(EXIT_FAILURE);
       }
       kill(list[i],SIGUSR1);

   }

   fclose(f_pids);

   alarm(N_SECS);

   sigprocmask(SIG_SETMASK, &old_mask, NULL);

   sigsuspend(&old_mask);

   



}




El problema es que sólo se elige un candidato, no pasa por varias rondas. Una salida: Candidato 7869 => [ Y Y Y N Y Y N N Y N ] =>Aceptado Candidato 7868 => [Finish by alarm

Por lo que he estado viendo el problema es que al hacer una segunda ronda se bloquean los procesos votantes




Si ya eres usuario del sistema, puedes contestar desde tu cuenta y así ganar prestigio.

Si sólo eres un visitante, puedes optar por...