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

时间:2020-02-14 15:09:05

标签: c concurrency semaphore shared-memory producer-consumer

像每个人一样,我试图更好地了解linux OS。我正在使用信号量实现生产者消费者同步问题。

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时,进程也不会停止。

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

2 个答案:

答案 0 :(得分:1)

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

基本上,您需要这样做:

  1. 一个信号量,用于统计等待消耗的数字。添加数字时post()的信号灯; wait()得到一个。

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

您可能还需要另一个信号量,该信号量限制了可以添加到段中的 条目的数量...您wait()获得添加条目以及其他过程的许可删除条目(从而释放插槽),使其post()继续等待。

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

答案 1 :(得分: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();

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

相关问题