Проблема в реализации синхронизации между производителем и потребителем с использованием семафоров - PullRequest
1 голос
/ 14 февраля 2020

Как и все, я пытался понять 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.производитель. 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;
}
потребитель. 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 ]

1 голос
/ 14 февраля 2020

Немного трудно понять ваше предназначение для трех семафоров, которые вы используете в своей логике c. Однако проблема в том, что вы «гоняете» за то, чтобы снять цифры. И ваша логика c слишком сложна.

В основном вам нужно это:

  1. A семафор , который подсчитывает количество чисел, которые являются ожидая, чтобы быть поглощенным. post() семафор при добавлении числа; wait() чтобы получить его.

  2. A mutex , который контролирует доступ к самому списку, так что только один поток одновременно может вставлять или удалять значения из сегмента.

Вам также может понадобиться другой семафор, который ограничивает количество записей, которые могут быть добавлены в сегмент ... вы wait() для разрешения чтобы добавить запись, и когда другие процессы удаляют запись (таким образом освобождая слот), они post() позволяют всем, кто ожидает, продолжить.

Наконец: то, что вы делаете здесь, это упражнение. В реальной жизни есть "трубы" и другие механизмы IP C, доступные "с полки", которые позаботятся об этих деталях для вас.

0 голосов
/ 14 февраля 2020

Здесь вы 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();

Тогда дубликаты добавлять не нужно.

...