使用信号量在生产者和消费者之间实现同步的问题

问题描述 投票:0回答:2

像所有人一样,我试图更好地了解linux操作系统。我正在使用信号量实现生产者消费者同步问题。

i)将有m个生产者过程和n个消费者过程。

ii)产品带有随机数。

iii)buffer在所有消费者和生产者过程之间共享,而in变量在所有生产者过程之间共享,out变量在所有消费者过程之间共享。

iv)一旦在终端中输入CTRL + C,所有进程将停止。

这里是代码:

1.shared.h

//assume all required headers included
#define buffer_size 5
#define empty_id 0
#define full_id 1
#define mutex_id 2
#define no_sem 3

struct sembuf signall = {0 , 1, 0};
struct sembuf wait = {0, -1, 0};

#define W(s) semop(s, &wait, 1);
#define S(s) semop(s, &signall, 1);
int shmid;
int *buffer;

union semun
{
                int val;
                struct semid_ds *buf;
                unsigned short  *array;
                struct seminfo  *__buf;

} setvalarg[3];


int *create_shared_mem_buffer()
{
        int *shmaddr;
        key_t key = ftok("/home/******/**/B", 1);
        shmid = shmget(key, buffer_size, IPC_CREAT|0660);
        shmaddr= (int *)shmat(shmid, NULL, 0);
        return shmaddr;
}


void clear_buffer()
{
        int i;
        for(i=0;i<buffer_size;i++)
                buffer[i]=0;
}

void releaseSHM(int signum)
{
        int status;
        clear_buffer();
        status = shmctl(shmid, IPC_RMID, NULL);

        status = kill(0, SIGKILL);
        exit(signum);
}


int create_semaphore_set()
{
        key_t key= ftok("/home/******/**/A", 1);

        int semid= semget(key, no_sem, IPC_CREAT|0600);

        setvalarg[0].val=buffer_size;
        semctl(semid, empty_id, SETVAL, setvalarg[0]);

        setvalarg[1].val=0;
        semctl(semid, full_id, SETVAL, setvalarg[1]);

        setvalarg[2].val=1;
        semctl(semid, mutex_id, SETVAL, setvalarg[2]);
        return semid;
}

2.producer.c

#include "shared.h"

void insert_product(int item, int *in, int *buffer)
{
        *in=(*in+1)%buffer_size;
        buffer[*in]=item;
        printf("Producer produces item %d stored in posn %d  \n",item,*in);
}

int shmid1;

int main(int argc, char *argv[])
{
        int i, pid, item;
        int *in;
        buffer = create_shared_mem_buffer();
        int semid= create_semaphore_set();

        sighandler_t shandler;

        shandler =  signal(SIGINT, releaseSHM);

        shmid1=  shmget(IPC_PRIVATE, sizeof(int),IPC_CREAT | 0777);
        in=(int *)shmat(shmid1, NULL, 0);
        *in=0;

        int m=5;

        for(i=0;i<m;i++)
        {
                pid=fork();
                if(pid==0)
                {
                        while(1)
                        {
                                item=rand();
                                wait.sem_num=0;
                                W(semid);
                                wait.sem_num=2;
                                W(semid);
                                insert_product(item, in, buffer);
                                signall.sem_num=2;
                                S(semid);
                                signall.sem_num=1;
                                S(semid);
                                sleep(2); //sleep has been introduced to slowdown the output.
                        }
                }
        }
        return 0;
}
  1. consumer.c
#include "shared.h"

int remove_product(int *out, int *buffer)
{
        int item;
        *out=(*out+1)%buffer_size;
        item=buffer[*out];
        buffer[*out]=0;
        return item;
}

int shmid1;

int main(int argc, char *argv[])
{
        int i, pid, item;
        int *out;
        buffer = create_shared_mem_buffer();
        int semid= create_semaphore_set();

        sighandler_t shandler;

        shandler =  signal(SIGINT, releaseSHM);
        shmid1=  shmget(IPC_PRIVATE, sizeof(int),IPC_CREAT | 0777);
        out=(int *)shmat(shmid1, NULL, 0);
        *out=-1;

        clear_buffer(buffer);

        int n=2;

        for(i=0;i<n;i++)
        {
                pid=fork();
                if(pid==0)
                {
                        while(1)
                        {
                                wait.sem_num=1;
                                W(semid);
                                wait.sem_num=2;
                                W(semid);
                                item=remove_product(out, buffer);
                                printf("Consumer consumes the product %d \n", item);
                                signall.sem_num=2;
                                S(semid);
                                signall.sem_num=0;
                                S(semid);
                                sleep(2); //sleep has been introduced to slow down the output
                        }
                }
        }
        return 0;
}

输出有点像这样:

Producer produces item 1681692777 stored in posn 2  
Producer produces item 1681692777 stored in posn 3  
Producer produces item 1681692777 stored in posn 4  
Producer produces item 1804289383 stored in posn 1  
Producer produces item 1804289383 stored in posn 2  
Producer produces item 1804289383 stored in posn 3  
Producer produces item 1804289383 stored in posn 0  
Producer produces item 1804289383 stored in posn 0  
Producer produces item 1681692777 stored in posn 0  
Producer produces item 1714636915 stored in posn 1  
Producer produces item 1714636915 stored in posn 2  
Producer produces item 1714636915 stored in posn 3  
Producer produces item 846930886 stored in posn 1  
Producer produces item 1714636915 stored in posn 4  
Producer produces item 846930886 stored in posn 2  
Producer produces item 1714636915 stored in posn 0  
Producer produces item 846930886 stored in posn 3  
Producer produces item 846930886 stored in posn 4  
Producer produces item 846930886 stored in posn 0  
Producer produces item 1681692777 stored in posn 1  
Consumer consumes the product 424238335 
Consumer consumes the product 424238335 
Consumer consumes the product 424238335 
Consumer consumes the product 424238335 
Consumer consumes the product 719885386 
Consumer consumes the product 719885386 
Consumer consumes the product 719885386 
Consumer consumes the product 719885386 
Consumer consumes the product 719885386 
Consumer consumes the product 1649760492 
Consumer consumes the product 1649760492 
Consumer consumes the product 596516649 
Consumer consumes the product 1649760492 
Consumer consumes the product 1649760492 
Consumer consumes the product 1649760492 
Consumer consumes the product 596516649 
Consumer consumes the product 596516649 
Consumer consumes the product 596516649 

如您所见,同一产品生产不止一次,而同一产品消耗不止一次。

i)有什么问题?如何解决?

ii)同样,当输入CTRL + C时,处理也不会停止。

我自己完成了所有操作,需要有人审核。如果需要更多信息,请在下面添加评论。

c concurrency semaphore shared-memory producer-consumer
2个回答
0
投票

很难理解您在逻辑中使用的三个信号量的预期目的。但是,问题在于您正在“争取”获得这些数字。而且您的逻辑太复杂了。

基本上,您需要这个:

  1. A semaphore计数等待被消耗的数字的数量。 post()添加数字时的信号灯; wait()得到一个。

  2. A mutex控制对列表本身的访问,因此一次只能有一个线程实际上可以从该段中插入或删除值。

您可能还需要另一个信号量,该信号量限制可以添加到段中的条目的数量...您wait()获得添加条目的权限,并且在其他进程删除条目时(因此释放插槽)post()让正在等待的任何人继续。

最后:您在这里所做的是运动。在现实生活中,“管道”和“现成的”其他IPC机制可为您提供这些细节。


0
投票

这里,您fork()进入了几个过程(对于m = 5,为五个):

    for(i=0;i<m;i++)
    {
            pid=fork();

并且在这里,您正在生成随机的项目编号:

            item=rand();

但是所有进程都使用相同的种子(1,因为您之前没有调用srand())!因此,所有分叉过程都生成相同的随机数序列。这就是您将每个项目添加5次的原因。尝试为每个进程的rng播种不同的数字,例如,在此处添加srand()

    for(i=0;i<m;i++)
    {
            srand(m);
            pid=fork();

然后,不应添加任何重复项。

© www.soinside.com 2019 - 2024. All rights reserved.