睡觉的理发师 - 共享内存队列不工作?

Sleeping barber - shared memory queue not working?

几天前我开始研究 sleeping barber problem, got some issues with segmentation fault But they have been solved here 即使我修复了缺失的部分,我仍然有问题。我需要使用 FIFO 队列,并为其创建共享内存。创建它时我没有收到任何错误。 运行 客户应该让我将 clientAmount 的客户放入队列中,理发师应该从中获取他们。每个客户都由他的进程 ID 描述。但是当我尝试这样做时,客户端程序显示客户端已添加到队列中:

2101 entered the queue
2099 entered the queue
2104 entered the queue
2097 entered the queue
2103 entered the queue
2095 entered the queue
2102 entered the queue
2098 entered the queue
2096 entered the queue

但是当我 运行 理发师代码时,我得到的是:

Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up

我不太确定在这里做什么。

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
int numberOfCuts;
int isCut;
int isDone;
void status(int f);
int main(int argc,char* argv[])
{

     if(argc < 3){
        printf("Error while executing program, invalid amount of arguments");
        return 0;
    }
    sem_t *barber;
    sem_t *queue;
    sem_t *client;
    sem_t *pillow;
    int clientsAmount;

    int sharedmem, waitRoomSize;
    struct Queue* waitroom;
    void *space;
    int i;
    signal(SIGUSR1, status);


    clientsAmount = atoi(argv[1]);
    numberOfCuts = atoi(argv[4]);

    barber = sem_open("/B", O_RDWR);
     if((barber == SEM_FAILED)){
        perror("Error while getting semaphore for barber");
        exit(1);
        }

    queue = sem_open("/Q", O_RDWR);
    if((queue  == SEM_FAILED)) {
        perror("Error while creating semaphore for queue");
        exit(1);
      }

    client = sem_open("/C", O_RDWR);
    if(client == SEM_FAILED){
        perror("Error while creating semaphore for pillow");
        exit(0);
      }

    sharedmem = shm_open("QueueMem", O_RDWR, 0666);
   if(sharedmem==-1){
       perror("Error while getting shared memory");
       exit(1);
    }
    space = mmap(NULL, sizeof(waitroom), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
   if((space == MAP_FAILED)){
       perror("Error while mapping memory");
       exit(1);
       }
    waitroom = (struct Queue*) space;


    for(i = 0; i< clientsAmount; i++){
        if(fork() == 0){
            int isCut = 0;

                 int id = getpid();
                 printf("%d entered the queue \n", id);
                    sem_wait(queue);

                    sem_post(queue);
                    if( push(waitroom, id)==-1){
                        printf("Queue is full, leaving...");
                        exit(0);
                    }else {
                    push(waitroom, id);
                    sem_wait(pillow);
                    printf("%d: Barber is sleeping, he needs to wake up", id);
                    int x;
                    sem_getvalue(barber, &x);
                    if(x==0){
                        sem_post(barber);
                        while(x!= 0){
                        sem_post(barber);
                        printf("Barber is waking up to cut %d", id);
                        }
                    }
                    sem_post(pillow);

                    _exit(0);
                    }

                }
            }






sem_close(barber);
    sem_unlink("/B");
    sem_close(queue);
    sem_unlink("/Q");
    sem_close(client);
    sem_unlink("/C");


}

void status(int f){
numberOfCuts--;
printf("Remaining cuts: %d", numberOfCuts);
isCut = 1;
while(!numberOfCuts)
{
    printf("Leaving the barber");
    isDone =1;
}
}

理发师代码:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#define BARBER "Barber"
int main(int argc,char* argv[])
{
    if(argc < 2){
        printf("Error while executing program, invalid amount of arguments");
        return 0;
    }
    sem_t *barber;
    sem_t *queue;

    sem_t *client;
    int seats;
    int sharedmem, waitRoomSize;
    struct Queue* waitroom;


    queue = sem_open("/Q", O_CREAT | O_RDWR, 0666, 1);
     if((queue  == SEM_FAILED)) {
        printf("Error while creating semaphore for queue");
        exit(1);
      }
      barber= sem_open("/B", O_CREAT | O_RDWR, 0666, 1);
     if((barber == SEM_FAILED)){
        printf("Error while creating semaphore for barber");
        exit(1);
        }
     client = sem_open("/C", O_CREAT | O_RDWR, 0666, 0);
      if(client == SEM_FAILED){
        printf("Error while creating semaphore for pillow");
        exit(0);
      }




    seats = atoi(argv[1]);
    void *space;



    sharedmem = shm_open("Queue",O_CREAT | O_RDWR, 0666);
    if(sharedmem==-1){
       printf("Error while getting shared memory");
       exit(1);
    }
    waitRoomSize = ftruncate(sharedmem, sizeof(waitroom));
    if((waitRoomSize ==-1)){
       printf("Error while getting size");
       exit(1);
       }
    space = mmap(NULL, sizeof(struct Queue), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
    if((space == MAP_FAILED)){
       printf("Bład podczas mapowania pamiêci");
       exit(1);
       }
    waitroom = (struct Queue*) space;

    queueinit(waitroom, seats);
    printf("semaphores created\n");




    while(1)
    {

     sem_post(queue);
     int x = isEmpty(waitroom);
     sem_wait(queue);
     if(x==1){
        printf("Queue empty, I fall asleep\n");
        sem_post(barber);
        sem_wait(barber);
        printf("I'm waking up\n");
     } else {
     sem_post(queue);

     int id = get(waitroom);
     sem_wait(queue);

     printf("%d, please sit on the chair\n", id);
     printf("Started cutting hair for %d\n", id);
     sleep(2);
     printf("Cutting done for :%d \n", id);

     kill(id, SIGUSR1);

     }
    }


    sem_close(barber);
    sem_unlink("/B");
    sem_close(queue);
    sem_unlink("/Q");
    sem_close(client);
    sem_unlink("/C");

    printf("senaphores unlinked");
    }

队列代码:

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>

struct Queue{
    int elems[500];
    int size;
    int queueIn;
    int queueOut;
    int isAsleep;
    int mainPID;
    int countCurrent;
};
void queueinit(struct Queue* q, int size){
    q->size = size;
    q->queueIn = q->queueOut = 0;
    q->isAsleep = 0;
    q->countCurrent = 0;

}

int push(struct Queue* q, int e){
    if(q->queueIn == ((q->queueOut -1 + q->size) % q->size)){
        return -1; //Queue full
    }

    q->elems[q->queueIn] = e;
    q->queueIn = (q->queueIn + 1) % q->size;
    return 0;
}

int get(struct Queue* q){
    int e = q->elems[q->queueOut];
    q->queueOut = (q->queueOut + 1) % q->size;
    return e;
}

int isEmpty(struct Queue* q){
    if(q->queueIn == q->queueOut)
        return 1;
    return 0;
}


void lock(sem_t* sem){
if(sem_wait(sem) == -1){
    printf("Error while lockin semaphore");
    exit(1);
}

}

void free_sem(sem_t* sem){
if(sem_post(sem) == -1){
    printf("Error while releasing semaphore");
    exit(1);
}

}

#endif // FUNCTIONS_H_INCLUDED

如有任何建议,我们将不胜感激

编辑 截至目前,几乎没有添加更改:

  1. 正在检查 sem_waitsem_post
  2. 的 return 值
  3. 删除了客户端
  4. 中对push(waitroom, id)的第二次调用
  5. 负责锁定和解锁信号量,主要是将 sem_waitsem_post 交换,反之亦然
  6. 摆脱了枕头信号量

现在程序几乎可以正常工作,但是在所有子项完成工作后客户端代码并没有退出。按 [ENTER] 有效。所以我接受了给定的建议并创建了一个新的信号量 - p,我锁定它而不是在客户端代码中使用 pause(),并在信号处理程序 status() 中解锁它。我还更改了初始化 barber 信号量的值——不再需要双重锁定或释放信号量。 我也尝试使用 abort() 函数而不是 exit 但它没有用。

现在发生了什么:

  1. Barber 代码确实启动了,但没有任何反应。
  2. 客户端代码启动并向队列添加一些值,然后立即退出。

理发师更新代码:

#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#define BARBER "Barber"
int main(int argc,char* argv[])
{
    if(argc < 2){
        printf("Error while executing program, invalid amount of arguments");
        return 0;
    }
    sem_t *barber;
    sem_t *queue;
    sem_t *p;
    int seats;
    int sharedmem, waitRoomSize;
    struct Queue* waitroom;


    queue = sem_open("/Q", O_CREAT | O_RDWR, 0666, 1);
     if((queue  == SEM_FAILED)) {
        printf("Error while creating semaphore for queue");
        exit(1);
      }
      barber= sem_open("/B", O_CREAT | O_RDWR, 0666, 0);
     if((barber == SEM_FAILED)){
        printf("Error while creating semaphore for barber");
        exit(1);
        }
    p= sem_open("/P", O_CREAT | O_RDWR, 0666, 0);
     if((p == SEM_FAILED)){
        printf("Error while creating semaphore for barber");
        exit(1);
        }



    seats = atoi(argv[1]);
    void *space;
    sharedmem = shm_open("QueueMem",O_CREAT | O_RDWR, 0666);

    if(sharedmem==-1){
       printf("Error while getting shared memory");
       exit(1);
    }
    waitRoomSize = ftruncate(sharedmem, sizeof(waitroom));
    if((waitRoomSize ==-1)){
       printf("Error while getting size");
       exit(1);
       }
    space = mmap(NULL, sizeof(struct Queue), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
    if((space == MAP_FAILED)){
       printf("Error while mapping memory");
       exit(1);
       }
    waitroom = (struct Queue*) space;

    queueinit(waitroom, seats);





    while(1)
    {

        lock(queue);
        if(isEmpty(waitroom)==1){
                printf("Queue empty, I fall asleep\n");
                waitroom->isAsleep = 1;
                free_sem(queue);
                lock(barber);

                printf("I'm waking up\n");

        } else {
            int id = get(waitroom);
            free_sem(queue);

            printf("%d, please sit on the chair\n", id);
            printf("Started cutting hair for %d\n", id);
            sleep(2);
            printf("Cutting done for :%d \n", id);

            kill(id, SIGUSR1);

     }
    }


    sem_close(barber);
    sem_unlink("/B");
    sem_close(queue);
    sem_unlink("/Q");
    sem_close(p);
    sem_unlink("/P");
    //exit(0);
    //printf("senaphores unlinked");
    }

客户端的更新代码:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
int numberOfCuts;

#include "functions.h"
int id;
sem_t *barber;
sem_t *queue;
sem_t *p;
int clientsAmount;

int sharedmem, waitRoomSize;
struct Queue* waitroom;
void *space;
void status(int f);
void handler(int f);



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

     if(argc < 3){
        printf("Error while executing program, invalid amount of arguments");
        return 0;
    }

    int i;
    signal(SIGUSR1, status);
    signal(SIGINT, handler);
    int pid = getpid();
    clientsAmount = atoi(argv[1]);
    numberOfCuts = atoi(argv[2]);

    barber = sem_open("/B", O_RDWR);
     if((barber == SEM_FAILED)){
        perror("Error while getting semaphore for barber");
        exit(1);
        }

    queue = sem_open("/Q", O_RDWR);
    if((queue  == SEM_FAILED)) {
        perror("Error while creating semaphore for queue");
        exit(1);
      }
    p = sem_open("/P", O_RDWR);
    if((p  == SEM_FAILED)) {
        perror("Error while creating semaphore for queue");
        exit(1);
      }


    sharedmem = shm_open("QueueMem", O_RDWR, 0666);
   if(sharedmem==-1){
       perror("Error while getting shared memory");
       exit(1);
    }
    space = mmap(NULL, sizeof(waitroom), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
   if((space == MAP_FAILED)){
       perror("Error while mapping memory");
       exit(1);
       }
    waitroom = (struct Queue*) space;


    for(i = 0; i< clientsAmount; i++) {
        if(fork() == 0) {
            id = getpid();
            printf("%d entered the barbershop \n", id);
            while(1) {

                lock(queue);
                if( push(waitroom, id)==-1 ) {
                   free_sem(queue);
                    printf("Queue is full, %d leaving...\n", id);
                    exit(0);
                } else {
                    free_sem(queue);
                    printf("%d has entered the queue \n", id);
                    lock(queue);
                    int x;
                    x = waitroom->isAsleep;
                    if(x==1){
                        printf("%d: Barber is sleeping, he needs to wake up\n", id);
                        waitroom->isAsleep = 0;
                        free_sem(queue);
                        free_sem(barber);
                        printf("Barber is waking up to cut %d\n", id);
                    } else {
                        printf("Barber is cutting someone else, %d waiting for its turn", id);
                        free_sem(queue);

                    }

                }
                lock(p);
            }

            break;
        }
    }


    //exit(0);
    sem_close(barber);
    sem_close(queue);
    sem_close(p);
    munmap(space, waitRoomSize);

    exit(0);

}


void handler(int f) {
    printf("Closing");
    sem_close(barber);
    sem_close(queue);

    munmap(space, waitRoomSize);

    exit(0);
}

void status(int f) {

    numberOfCuts--;
    free_sem(p);
    printf("Remaining cuts for %d: %d\n", id, numberOfCuts);

    if(!numberOfCuts) {

        printf("%d is done cutting \n", id);

        exit(0);
    }

}

你的程序有几个错误:

  1. 在客户端代码中,您正在调用 sem_wait(pillow)sem_post(pillow);,尽管变量 pillow 尚未初始化。这会导致未定义的行为。为了初始化信号量,您可以使用函数 sem_initsem_open.
  2. 在客户端代码中,您在获取互斥锁后立即释放queue。相反,您应该只在完成队列操作后才释放它。
  3. 在客户端代码中,您调用了两次 push(waitroom, id),第二次调用紧接在第一次调用之后。这没有意义。
  4. 在理发师的主循环中,您释放了互斥量 queuebarber 而不是事先获取它们,然后再获取它们。通常应该首先获取互斥锁,然后释放,而不是相反。使用 sem_wait 获取互斥量,使用 sem_post 释放它。编辑:与此同时,我相信您正在使用信号量 barber 来发出信号,而不是作为互斥量。在那种情况下,调用 sem_post 而不事先调用 sem_wait 是正确的。
  5. 您没有检查 sem_wait 的 return 值。例如,可能由于信号处理程序中断而导致函数失败。
  6. 在信号处理程序中使用函数 printf 是不安全的。有关详细信息,请参阅 this link
  7. 在终止父进程之前,您没有等待子进程完成。