Marcin Majewski
Marcin Majewski

Reputation: 1047

Shared memory and POSIX semaphores

I wrote simple consumer-producer program in C. It is working fine while I have 1 producer and 1 consumer. But it is acting strange when I increase number of consumers.

  1. I start the producer process
  2. Producer is producing
  3. I start the consumer process
  4. Consumer is consuming and producer is producing
  5. I start the consumer process no 2
  6. Consumer process no2 never gets an element
  7. When I start consumer no3, no4... and so on, the same happens

Second problem:

  1. Producer produced maximum of elements
  2. Consumer consumes all elements, but producer does not continue to produce anymore

I have no idea why it is happening.

Code:

Producer:

#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include "common.h"

int memoryID;
struct wrapper *memory;
int rc;

void atexit_function() {
    rc = shmctl(memoryID, IPC_RMID, NULL);
    rc = shmdt(memory);
    sem_destroy(&memory->pmutex);
    sem_destroy(&memory->cmutex);
    sem_destroy(&memory->empty);
    sem_destroy(&memory->full);
}

int main(int argc, char **argv) {
    atexit(atexit_function);
    //creating key for shared memory
    srand(time(NULL));
    key_t sharedMemoryKey = ftok(".", MEMORY_KEY);
    if (sharedMemoryKey == -1) {
        perror("ftok():");
        exit(1);
    }

    memoryID = shmget(sharedMemoryKey, sizeof(struct wrapper), IPC_CREAT | 0600);
    if (memoryID == -1) {
        perror("shmget():");
        exit(1);
    }

    memory = shmat(memoryID, NULL, 0);
    if (memory == (void *) -1) {
        perror("shmat():");
        exit(1);
    }

    //initialization

    printf("Initializtaion !\n");
    memset(&memory->array, 0, sizeof(memory->array));
    sem_init(&memory->pmutex, 0, 1);
    sem_init(&memory->cmutex, 0, 1);
    sem_init(&memory->empty, 0, SIZE_OF_ARRAY);
    sem_init(&memory->full, 0, 0);
    memory->n = -1;

    if (memoryID == -1) {
        perror("shmget(): ");
        exit(1);
    }


    while(1)
    {
        int r = rand();
        sem_wait(&memory->empty);
        sem_wait(&memory->pmutex);
        memory->n++;
        (memory->array)[memory->n]=r;
        printf("Adding task\t Value:%d\tNumber of tasks waiting:%d \n",r,memory->n);
        usleep(10000);
        sem_post(&memory->pmutex);
        sem_post(&memory->full);
    }

}

Consumer:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include <sys/shm.h>

int memoryID;
struct wrapper *memory;
int check_prime(int a);
int main(int argc, char **argv) {
    srand(time(NULL));
    key_t sharedMemoryKey = ftok(".",MEMORY_KEY);
    if(sharedMemoryKey==-1)
    {
        perror("ftok():");
        exit(1);
    }
    memoryID=shmget(sharedMemoryKey,sizeof(struct wrapper),0);

    if(memoryID==-1)
    {
        perror("shmget(): ");
        exit(1);
    }

    memory = shmat(memoryID,NULL,0);
    if(memory== (void*)-1)
    {
        perror("shmat():");
        exit(1);
    }

    while(1)
    {
        sem_wait(&memory->full);
        sem_wait(&memory->cmutex);

        int n = memory->n;
        int temp = (memory->array)[n];
        printf("Removed item: %d\tPrime:%d\tNumer of tasks left:%d\n",
            temp, check_prime(temp),n);
        memory->n--;
        usleep(10000);

        sem_post(&memory->cmutex);
        sem_post(&memory->empty);
    }

}

common.h:

#define MEMORY_KEY 12
#define SIZE_OF_ARRAY 10
struct wrapper
{
    int array[SIZE_OF_ARRAY];
    sem_t empty;
    sem_t pmutex;
    sem_t cmutex;
    sem_t full;
    int n;
};

Upvotes: 1

Views: 3974

Answers (1)

Marcin Majewski
Marcin Majewski

Reputation: 1047

Problem solved. I was setting int sem_init(sem_t *sem, int pshared, unsigned int value); I was setting pshared value to 0 but:

   The pshared argument indicates whether this semaphore  is  to  be  shared  between  the
   threads of a process, or between processes.

  If  pshared  has  the  value  0,  then the semaphore is shared between the threads of a
   process, and should be located at some address that is visible to all threads (e.g.,  a
   global variable, or a variable allocated dynamically on the heap).

  If  pshared  is  nonzero, then the semaphore is shared between processes, and should be
   located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)).  (Since
   a  child  created  by fork(2) inherits its parent's memory mappings, it can also access
   the semaphore.)  Any process that can access the shared memory region  can  operate  on
   the semaphore using sem_post(3), sem_wait(3), etc.

Upvotes: 1

Related Questions