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

Posted

技术标签:

【中文标题】睡觉的理发师 - 共享内存队列不起作用?【英文标题】:Sleeping barber - shared memory queue not working? 【发布时间】:2021-01-08 23:03:36 【问题描述】:

几天前我开始研究sleeping barber problem,遇到了一些分段错误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

任何建议将不胜感激

编辑 到目前为止,几乎没有添加任何更改:

    检查sem_waitsem_post的返回值 删除了客户端中对 push(waitroom, id) 的第二次调用 负责锁定和解锁信号量,主要将sem_waitsem_post 交换,反之亦然 摆脱了枕头信号量

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

现在发生了什么:

    理发店代码启动,但没有任何反应。 客户端代码启动并向队列添加一些值,然后立即退出。

理发师的更新代码:

#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。 在客户端代码中,您在获取互斥锁queue 后立即释放它。相反,您应该仅在完成队列操作后才释放它。 在客户端代码中,您调用了两次push(waitroom, id),第二次调用紧接在第一次调用之后。这没有意义。 在理发师的主循环中,您将释放互斥锁queuebarber,而无需事先获取它们,然后再获取它们。互斥锁通常应该首先被获取,然后被释放,而不是相反。使用sem_wait 获取互斥锁,sem_post 释放它。编辑:同时,我相信您将信号量 barber 用于信号目的,而不是作为互斥体。在这种情况下,调用sem_post 而不事先调用sem_wait 是正确的。 您没有检查sem_wait 的返回值。例如,函数可能由于被信号处理程序中断而失败。 在信号处理程序中使用函数printf 是不安全的。请参阅this link 了解更多信息。 在终止父进程之前,您无需等待子进程完成。

【讨论】:

我考虑了您提出的所有建议,并在程序上取得了一些进展。但有一件事仍然困扰着我——客户端程序根本没有退出,即使所有客户端都完成了削减。我有status() 函数,它应该检查每个客户端的切割次数,它会正确打印它们,它还会打印消息“814 切割完成”,几秒钟后我可以按 Enter 键并程序结束,但不是在它的拥有应有的权利。 @krysznys:您没有检查sem_wait 的返回值以查看是否成功获取互斥锁。例如,如果函数因为被信号处理程序中断而失败,您的程序将错误地认为互斥锁已成功获取。 我这样做了,但是客户端代码在完成所有它应该做的事情后仍然没有退出。我更新了帖子中的代码。 @krysznys:函数signal 的行为非常特定于平台,即使在符合 POSIX 的系统上也是如此。你在使用带有 glibc 的 Linux 吗? @krysznys:如果您使用的是 Linux,那么在异步信号处理程序中使用函数 printf 是不安全的。请参阅this link 了解更多信息。

以上是关于睡觉的理发师 - 共享内存队列不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

用信号量保护共享内存段不起作用

pthread读写锁不起作用吗? [关闭]

更改 NSURLCache 内存和磁盘容量不起作用

删除智能指针的内存释放不起作用[重复]

为啥此 Google+ 基本共享不起作用?

Livewire 队列作业调度 afterRespone() 不起作用