Значения семафоров не меняются в Ubuntu - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь создать решение для проблемы перехода через реку из «Маленькой книги семафоров» (глава 5, раздел 7, стр. 148), я использую виртуальную машину Ubuntu на моем ПК.

Проблема в том, что созданные мной семафоры не меняют значений, все они остаются на 0, я использую четыре файла.

Что я делаю, запускаю буфер, а затем создаю два хакерских процесса изатем два крепостных процесса, дело в том, что сообщение «Boarding X» печатается до того, как лодка заполнена (как минимум, четыре пассажира), и когда я печатаю значения семафора, все они находятся в заголовке 0.

.h, где я объявляю идентификаторы и операции семафоров:

#ifndef SEMAFOROS_H
#define SEMAFOROS_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define BARRIER     10
#define MUTEX       11
#define SERFQUEUE   12
#define HACKERQUEUE 13

struct buffer {
    int hackers;
    int serfs;
};

int sem_wait(int semid, int sem_num, int val) {
    struct sembuf op;

    op.sem_num = sem_num;
    op.sem_op = -val;
    op.sem_flg = 0;
    return semop(semid, &op, 1);
}

int sem_signal(int semid, int sem_num, int val) {
    struct sembuf op;

    op.sem_num = sem_num;
    op.sem_op = val;
    op.sem_flg = 0;
    return semop(semid, &op, 1);
}

int mutex_wait(int semid, int sem_num) {
    return sem_wait(semid, sem_num, 1);
}

int mutex_signal(int semid, int sem_num) {
    return sem_signal(semid, sem_num, 1);
}

#endif

buffer.c, где я создаю семафоры:

#include "header.h"

int main(int argc, char* argv[])
{
    int semid, shmid, i;
    key_t key;

    if (argc != 1) {
        printf("usage: %s\n", argv[0]);
        return -1;
    }

    if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
        perror(argv[0]);
        return -1;
    }

    if ( (semid = semget(key, 4, 0666 | IPC_CREAT))  < 0 ) {
        perror(argv[0]);
        return -1;
    }

    semctl(semid, BARRIER, SETVAL, 4);
    semctl(semid, MUTEX, SETVAL, 1);
    semctl(semid, SERFQUEUE, SETVAL, 0);
    semctl(semid, HACKERQUEUE, SETVAL, 0);

    unsigned short final_values[4];
    semctl(semid, 0, GETALL, final_values);
    for (i = 0; i < 4; i++) {
        printf("%3i", final_values[i]);
    }
    printf("\n");

    if ( (shmid = shmget(key, sizeof(struct buffer), 0666 | IPC_CREAT)) < 0) {
        semctl(semid, 0, IPC_RMID, 0);
        perror("shmget");
        return -1;
    }

    struct buffer *b = (struct buffer *) shmat(shmid, (void *) 0, 0);   
    b->hackers = 0;
    b->serfs = 0;
    shmdt(b);

    return 0;
}

hackers.c, код для хакеров:

#include "header.h"
#include <time.h>

void a_hacker(char* program) {
    int semid, shmid, i, k, isCaptain = 0;
    key_t key;
    struct buffer *b;

    if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
        perror(program);
        exit(-1);
    }

    if ( (semid = semget(key, 4, 0666))  < 0 ) {
        perror(program);
        exit(-1);
    }

    if ( (shmid = shmget(key, sizeof(struct buffer), 0666)) < 0 ) {
        perror("shmid");
        exit(-1);
    }   
    b = (struct buffer *) shmat(shmid, (void *) 0, 0);

    mutex_wait(semid, MUTEX);
    b->hackers += 1;

    if (b->hackers == 4) {
        sem_signal(semid, HACKERQUEUE, 4);
        b->hackers = 0;
        isCaptain = 1;
    } else if (b->hackers == 2 && b->serfs >= 2) {
        sem_signal(semid, HACKERQUEUE, 2);
        sem_signal(semid, SERFQUEUE, 2);
        b->hackers = 0;
        b->serfs -= 2;
        isCaptain = 1;
    } else {
        mutex_signal(semid, MUTEX);
    }

    unsigned short final_values[4];
    semctl(semid, 0, GETALL, final_values);
    for (i = 0; i < 4; i++) {
        printf("%3i", final_values[i]);
    }
    printf("\n");

    sem_wait(semid, HACKERQUEUE, 1);

    printf("Boarding a hacker\n");

    semctl(semid, 0, GETALL, final_values);
    for (i = 0; i < 4; i++) {
        printf("%3i", final_values[i]);
    }
    printf("\n");

    sem_wait(semid, BARRIER, 1);

    if (isCaptain) {
        printf("Fugaaaa\n");
        mutex_signal(semid, MUTEX);
    }

    sem_signal(semid, BARRIER, 2);
    shmdt(b);
    exit(0);
}

int main(int argc, char* argv[]) {
    int amount_hackers = 0, semid, i, pid;
    key_t key;

    if (argc != 2) {
        printf("usage: %s amount_of_serfs amount_of_hackers\n", argv[0]);
        return -1;
    }

    amount_hackers = atoi(argv[1]);
    if (amount_hackers < 1) {
        printf("%s: The amount_of_hackers must be a positive number greater than zero.\n", argv[0]);
        return -1;
    }

    for (i = 0; i < amount_hackers; i++) {
        if ( (pid = fork()) < 0 ) {
            perror("fork");
            return -1;
        } else if (pid == 0) {
            a_hacker(argv[0]);
        } else {
        }
    }

    return 0;
}

serfs.c, код для крепостных:

#include "header.h"
#include <time.h>

void a_serf(char* program) {
    int semid, shmid, i, k, isCaptain = 0;
    key_t key;
    struct buffer *b;

    if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
        perror(program);
        exit(-1);
    }

    if ( (semid = semget(key, 4, 0666))  < 0 ) {
        perror(program);
        exit(-1);
    }

    if ( (shmid = shmget(key, sizeof(struct buffer), 0666)) < 0 ) {
        perror("shmid");
        exit(-1);
    }   
    b = (struct buffer *) shmat(shmid, (void *) 0, 0);

    mutex_wait(semid, MUTEX);
    b->serfs += 1;

    if (b->serfs == 4) {
        sem_signal(semid, SERFQUEUE, 4);
        b->serfs = 0;
        isCaptain = 1;
    } else if (b->hackers == 2 && b->serfs >= 2) {
        sem_signal(semid, HACKERQUEUE, 2);
        sem_signal(semid, SERFQUEUE, 2);
        b->serfs = 0;
        b->hackers -= 2;
        isCaptain = 1;
    } else {
        mutex_signal(semid, MUTEX);
    }

    unsigned short final_values[4];
    semctl(semid, 0, GETALL, final_values);
    for (i = 0; i < 4; i++) {
        printf("%3i", final_values[i]);
    }
    printf("\n");

    sem_wait(semid, SERFQUEUE, 1);

    printf("Boarding a serf\n");

    semctl(semid, 0, GETALL, final_values);
    for (i = 0; i < 4; i++) {
        printf("%3i", final_values[i]);
    }
    printf("\n");

    sem_wait(semid, BARRIER, 1);

    if (isCaptain) {
        printf("Fugaaaa\n");
        mutex_signal(semid, MUTEX);
    }

    sem_signal(semid, BARRIER, 2);
    shmdt(b);
    exit(0);
}

int main(int argc, char* argv[]) {
    int amount_serfs = 0, semid, i, pid;
    key_t key;

    if (argc != 2) {
        printf("usage: %s amount_of_serfs amount_of_hackers\n", argv[0]);
        return -1;
    }

    amount_serfs = atoi(argv[1]);
    if (amount_serfs < 1) {
        printf("%s: The amount_of_serfs must be a positive number greater than zero.\n", argv[0]);
        return -1;
    }

    for (i = 0; i < amount_serfs; i++) {
        if ( (pid = fork()) < 0 ) {
            perror("fork");
            return -1;
        } else if (pid == 0) {
            a_serf(argv[0]);
        } else {
        }
    }

    return 0;
}

Может кто-нибудь помочь мне?

...