0

I have written this Producer/Consumer Problem solution. It seems to be working, other than the infinite loop. I was under the impression that pthread_exit(NULL); would make it stop, but honestly, I've become lost and confused. Could someone point me in the right direction of how to stop the loop?

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<iostream>
#include<semaphore.h>

#define BUFFSIZE 10

using namespace std;

int buffer[BUFFSIZE];
int size; //current buffer size
int n = 0, m = 0;

pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;

sem_t Available;
sem_t Buffer; //indicates if buffer is full

//----------------------------------------------------------------//

void *Consumers(void *argument)
{
    int con_id = *((int *) argument);
    while(1)
    {
        if(size == 0)
        {
            cout << "Queue is empty." << endl;
        }

        sem_wait(&Available);
        pthread_mutex_lock(&Mutex);

        size--;
        cout << "Con " << con_id << ": Product removed from buffer" << endl;
        //for(int i = 0; i < size; i++)
        //{
        //  cout << Buffer[i] << " ";
        //}
        cout << endl;
        pthread_mutex_unlock(&Mutex);
        sem_post(&Buffer);
    }
    return(NULL);
}

//----------------------------------------------------------------//

void *Producers(void *argument)
{
    int item = 8;
    int pro_id = *((int *) argument);

    while(1)
    {
        sem_wait(&Buffer);
        pthread_mutex_lock(&Mutex);
        //Buffer[size] = item;
        cout << "Item added" << endl;
        size++;
        pthread_mutex_unlock(&Mutex);
        sem_post(&Available);
    }
    return(NULL);
}

//----------------------------------------------------------------//

int main()
{

    cout << "Enter number of producers: " << endl;
    scanf("%d", &n);
    cout << "Enter number of consumers: " << endl;
    scanf("%d", &m);
    //get number of producers(int n), and consumers(int m)
    sem_init(&Available, 0, 0);
    sem_init(&Buffer, 0, BUFFSIZE);

    pthread_t *con = new pthread_t[m];
    int *thread_args_c = new int[m];
    for(int i = 0; i < n; i++)
    {
        thread_args_c[i] = i;
        pthread_create(&con[i], NULL, Consumers, (void*) &i);
    }

    pthread_t *pro = new pthread_t[n];
    int *thread_args_p = new int[n];
    for(int i = 0; i < n; i++)
    {
        thread_args_p[i] = i;
        pthread_create(&pro[i], NULL, Producers, (void*) &i);
        pthread_join(con[i], NULL);
    }

    pthread_exit(NULL);

}
SergeyA
  • 61,605
  • 5
  • 78
  • 137
Tangwheeler
  • 207
  • 1
  • 11
  • Data race on `main()`s `int i` variables, the addresses of which are passed to threads that read from them, while `main()` modifies them. Also, `&i` is used after `i`s lifetime has ended. – EOF Feb 19 '16 at 21:52

2 Answers2

1

Not sure what you are expecting. pthread_exit appears in the end of the main (and completely not needed there, since main is exiting anyways), but your enless loops inside thread will never let main reach this point (since you are joining the consumers thread).

Also, your creation and joining model makes litle sense - what's the point of joining consumer thread after you've created a producer?

And last, but not the lease, you fail to join producer thread.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
0

The loops will not stop because there is no logic in the code to actually exit the loop.

The process is stuck because pthread_join suspends the calling thread till the target exits. See documentation for pthread_join

If you don't care about actually terminating the threads and returning to the main thread, just remove the call to pthread_join. The process should terminate because the main thread exited.

To actually properly terminate the loops, you need to set an internal or external trigger. You could internally have the loops exit after a set number of iterations. For this, you will do while(x<=y) instead of while(1).

You could also make it more complicated and have the main thread signal the other threads externally that it wants the other threads to shut down. You can have the main thread set a (volatile) boolean when you are ready to exit and have the other threads break the loop based on it. If you care about the Atomicity of the exit, you will need to protect the boolean with a lock.

rs557
  • 9
  • 3
  • The answer is not complete regarding the boolean. – SergeyA Feb 19 '16 at 19:21
  • @SergeyA This answers the original question of "how to stop the loop". I didn't believe it necessary to go in to detail about how a stop signal may be synchronized for atomicity. That is probably a question in itself, one that has likely been answered elsewhere. – rs557 Feb 19 '16 at 19:35
  • You still mentioned the lock! One might concur that if you do not want the atomicity of exit, you can use a simple boolean. Is that your message? – SergeyA Feb 19 '16 at 19:41
  • @SergeyA Yes, that is what I meant to convey. If one doesn't care about immediately exiting the thread after signalling a stop, one might as well use a global boolean. The threads will eventually read an updated value of the global variable and exit. Otherwise, one might want to look in to the various synchronization mechanisms at one's disposal. – rs557 Feb 19 '16 at 20:21
  • *The threads will eventually read an updated value of the global variable* this is just wrong. – SergeyA Feb 19 '16 at 20:24
  • @SergeyA Care to elaborate? Is it always wrong? Is there a specific condition under which it is wrong? – rs557 Feb 19 '16 at 21:05
  • Yes, I do care to elaborate. In all likeliness, threads will **never** see updated global variable. – SergeyA Feb 19 '16 at 21:06
  • You are right. I need to specify that the boolean needs to be a `volatile` in order to avoid continuously reading the stale value. Thank you! – rs557 Feb 19 '16 at 21:27
  • No. volatile in regards to threading is MSVC-specific, and generally can not be used to achieve what you are trying to do. – SergeyA Feb 19 '16 at 21:32