我有一个C语言竞赛程序,无论什么情况,它总是有相同的获胜者

时间:2019-05-30 16:07:06

标签: c signals semaphore

以下程序由命名信号量控制,并且应该执行此操作:

  1. 主流程将创建N_PROC个孩子,并为每个孩子分配一个ID(对于已创建的第一个孩子, 0 ;对于第二个孩子, 1 一个等等)。
  2. 每个孩子都通过使用pause()等待父亲的信号。
  3. 主进程向他的孩子发送SIGUSR1信号。
  4. 每个孩子重复一次直到他们死:他们打开一个文件(所有孩子都使用同一文件),写他们的id,关闭该文件,然后在1到100之间的任意毫秒数内睡眠。
  5. 每秒,主进程打开与他的孩子相同的文件,计算每个id出现的次数(在读取它们时打印它们),如果孩子写了20次id,则声明该孩子优胜者,向他的所有孩子发送SIGTERM,等待他们完成,然后删除信号灯。

我的问题是,无论我重新编译或重新运行该程序多少次,父级始终会打印相同的内容,因此2号子级始终是赢家。

谢谢。

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

#define SEM1 "/example_sem1"
#define SEM2 "/example_sem2"
#define SEM3 "/example_sem3"

#define FFILE "ejercicio9.txt"

#define N_PROC 3

int valor_semaforo(sem_t *sem) {
    int sval;

    if (sem_getvalue(sem, &sval) == -1) {
        perror("sem_getvalue");
        sem_unlink(SEM1);
        sem_unlink(SEM2);
        sem_unlink(SEM3);
        exit(EXIT_FAILURE);
    }
    return sval;
}

int main(void) {
    sem_t *sem_write = NULL, *sem_read = NULL, *sem_count = NULL;
    pid_t pid[N_PROC];
    int i, numero, num[N_PROC], t;
    struct sigaction act;
    FILE *fp;
    srand(time(NULL) + getpid());

    if ((sem_write = sem_open(SEM1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    if ((sem_read = sem_open(SEM2, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    if ((sem_count = sem_open(SEM3, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }

    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;

    act.sa_handler = SIG_IGN;
    if (sigaction(SIGUSR1, &act, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }    

    for (i = 0; i < N_PROC; i++) {
        num[i] = 0;
        pid[i] = fork();
        if (pid[i] < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        if (pid[i] == 0) {
            pause();
            while (1) {
                sem_wait(sem_write);
                fp = fopen(FFILE, "a+");
                fprintf(fp, "%d ", i);
                fclose(fp);
                sem_post(sem_write);
                usleep(1 + (rand() % 100));
            }
        }
    }

    kill(0, SIGUSR1);
    while (1) {
        sleep(1);
        sem_wait(sem_read);
        sem_post(sem_count);
        if (valor_semaforo(sem_count) == 1)
            sem_wait(sem_write);
        sem_post(sem_read);

        fp = fopen(FFILE, "r");
        while (fscanf(fp, "%d", &numero) > 0) {
            printf("%d ", numero);
            fflush(stdout);
            for (i = 0; i < N_PROC; i++) {
                if (numero == i)
                    (num[i])++;
                if (num[i] == 20) {
                    printf("\nHa finalizado la carrera: el ganador es el proceso %d\n", i);
                    fflush(stdout);

                    act.sa_handler = SIG_IGN;
                    if (sigaction(SIGTERM, &act, NULL) < 0) {
                        perror("sigaction");
                        exit(EXIT_FAILURE);
                    }    

                    kill(0, SIGTERM);
                    while (wait(NULL) > 0);
                    sem_close(sem_write);
                    sem_close(sem_read);
                    sem_close(sem_count);
                    sem_unlink(SEM1);
                    sem_unlink(SEM2);
                    sem_unlink(SEM3);
                    fclose(fp);
                    exit(EXIT_SUCCESS);    
                }
            }
        }
    }

    printf("\n");
    fflush(stdout);
    fp = fopen(FFILE, "w+");
    fclose(fp);

    sem_wait(sem_read);
    sem_wait(sem_count);
    if (valor_semaforo(sem_count) == 0)
        sem_post(sem_write);
    sem_post(sem_read);
}

1 个答案:

答案 0 :(得分:1)

在扫描文件之前,请勿重置num阵列。碰巧在您的系统上,第三个孩子首先写入了文件。

在使用以下方法解析文件之前,应清除此数组:

memset(num, 0, sizeof num);

for (i = 0; i < N_PROC; i++)
    num[i] = 0;