Search code examples
cmultithreadingpthreadsproducer-consumer

Producer/Consumer in C with pthread semaphores and multiple threads


Lets say I have a buffer that has 3 producer threads and 5 consumer threads inserting and consuming to/from the buffer.

I only want to allow 1 producer or up to 3 consumer threads access the buffer at any given time.

Up to 3 consumers can peek at the top element in the buffer, only, if no producer is accessing it. If more than 1 consumer thread does access the buffer, the last thread to leave must delete the top element.

Now this is part of a class assignment, and the assignment explicitly states to use semaphores. However, I can't think of a way to really implement this wording exactly using only semaphores.

The pseudo code -I think- should look like this: (I'm not worrying about an empty or full buffer, just this sub-part of the problem)

sem_init(&binary, 0, 1);  //Init binary semaphore to 1
sem_init(&consumerCount, 0 , 3);  //Allows 3 consumers to access

producer()
{
    createItem()
    sem_wait(&binary)
    appendItem()
    sem_post(&binary)
}

//The above assures nothing else can access buffer while appending an item

consumer()
{

    while( binary unlocked)
    {
        sem_wait(&binary) and sem_wait(&consumerCount)  //Locks the producers out
                                                        //Allows 3 consumers in 
        peek()  //Gets copy of top item
        if( last consumer out )
        {
            delete()  //Deletes top item
            sem_post(&binary)  //Allow producer access back since last one out
        }
        sem_post(&consumerCount)         

    }
}

I think that's the gist of the logic, problem is how to implement this with just semaphores. How do I allow only 1 producer in with a semaphore but allow 3 consumers in on the other side? It seems like I would need to use something besides a semaphore.

Also, please correct any of the logic if needed, this is meant to just be a general idea.


Solution

  • You can solve the problem with two semaphores. The first semaphore is used for exclusive access by producers. The second semaphore is used for the shared access. The producer tries to acquire all three permits in order to lock out the consumers.

    sem_init(&exclusive, 0, 1);
    sem_init(&shared, 0, 3);
    
    void producer()
    {
        sem_wait(&exclusive);
        sem_wait(&shared);
        sem_wait(&shared);
        sem_wait(&shared);
        // critical section
        sem_post(&shared);
        sem_post(&shared);
        sem_post(&shared);
        sem_post(&exclusive);
    }
    
    void consumer()
    {
        sem_wait(&shared);
        // critical section
        sem_post(&shared);
    }