0

I was asked a question in HP interview. There is 1 buffer.There is 1 Producer thread and 2 consumer thread. How will you synchronize?My answer was

struct Node
{
    int data;
    Node * next;
    Node * lastPrev;
}*buffer;

sem_t semaphore,sem2;
pthread_mutex_t lock,mut;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

int global=0;

void writeToBuffer(int i)
{

    if(!buffer)
    {
        buffer= new Node;
        buffer->next=0;
        buffer->data=i;
        buffer->lastPrev=0;
    }
    else
    {
        if(buffer && !buffer->lastPrev)
        {
            buffer->next=new Node;
            buffer->lastPrev=buffer;
            buffer->lastPrev->next->next=0;
            buffer->lastPrev->next->data=i; 
        }
        else
        {
            buffer->lastPrev->next->next=new Node;
            buffer->lastPrev= buffer->lastPrev->next;
            buffer->lastPrev->next->next =0;
            buffer->lastPrev->next->data=i; 
        }
    }
}

void printBuffer()
{
    for(Node*temp=buffer;temp!=0;temp=temp->next)
    {
        cout<<temp->data<<"-";
    }
    cout<<endl<<"##############################################"<<endl;
}

Node* getBufferFront()
{
    if(buffer==0)
    {
        return 0;
    }
    else
    {
        Node*temp = buffer;
        buffer=buffer->next;
        if(buffer && buffer->next && !buffer->next->next)
        {
            buffer->lastPrev=buffer;
        }
        else if(buffer && !buffer->next)
        {
            buffer->lastPrev=0;
        }
        return temp;
    }
}

void* producer(void * arg)
{
    int i=0;
    cout<<"entered producer"<<endl;
    while(i++!=15)
    {
        //cout<<i<<"-";
        pthread_mutex_lock(&lock);
        writeToBuffer(i);
        pthread_mutex_unlock(&lock);
        printBuffer();
        sem_post(&semaphore);
    }
    cout<<endl;
}

void* consumer1(void * arg)
{
    while(1)
    {

            sem_wait(&semaphore);
            pthread_mutex_lock(&lock);
            Node* temp = getBufferFront();
            pthread_mutex_unlock(&lock);  
            if(temp)
                cout<<"data consumed by consumer1="<<temp->data<<endl;
            else cout<<"NULL"<<endl;
            printBuffer();
            delete(temp);

    }

}

void* consumer2(void* arg)
{

    while(1)
    {

            sem_wait(&semaphore);
            pthread_mutex_lock(&lock);
            Node* temp = getBufferFront();
            pthread_mutex_unlock(&lock);  
            if(temp)
                cout<<"data consumed by consumer2="<<temp->data<<endl;
            else cout<<"NULL"<<endl;
            printBuffer();
            delete(temp);


    }
}

int main()
{
    pthread_t  th1,th2,th3;


    sem_init(&semaphore,0,0);

    if (pthread_mutex_init(&lock, NULL) != 0)
    {
        cout<<" mutex init has failed"<<endl;
        return 1;
    }


    buffer=0;


    pthread_create(&th1,0,producer,0);
    pthread_create(&th2,0,consumer1,0);
    pthread_create(&th3,0,consumer2,0);
    pthread_join(th1,0);
    pthread_join(th2,0);
    pthread_join(th3,0);
}

Then he told it will not balance load. You have to divide task equally between them. I suggested to use condition variables.Like this->

struct Node
{
    int data;
    Node * next;
    Node * lastPrev;
}*buffer;

sem_t semaphore,sem2;
pthread_mutex_t lock,mut;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

int global=0;

void writeToBuffer(int i)
{

    if(!buffer)
    {
        buffer= new Node;
        buffer->next=0;
        buffer->data=i;
        buffer->lastPrev=0;
    }
    else
    {
        if(buffer && !buffer->lastPrev)
        {
            buffer->next=new Node;
            buffer->lastPrev=buffer;
            buffer->lastPrev->next->next=0;
            buffer->lastPrev->next->data=i; 
        }
        else
        {
            buffer->lastPrev->next->next=new Node;
            buffer->lastPrev= buffer->lastPrev->next;
            buffer->lastPrev->next->next =0;
            buffer->lastPrev->next->data=i; 
        }
    }
}

void printBuffer()
{
    for(Node*temp=buffer;temp!=0;temp=temp->next)
    {
        cout<<temp->data<<"-";
    }
    cout<<endl<<"##############################################"<<endl;
}

Node* getBufferFront()
{
    if(buffer==0)
    {
        return 0;
    }
    else
    {
        Node*temp = buffer;
        buffer=buffer->next;
        if(buffer && buffer->next && !buffer->next->next)
        {
            buffer->lastPrev=buffer;
        }
        else if(buffer && !buffer->next)
        {
            buffer->lastPrev=0;
        }
        return temp;
    }
}

void* producer(void * arg)
{
    int i=0;
    cout<<"entered producer"<<endl;
    while(i++!=15)
    {
        //cout<<i<<"-";
        pthread_mutex_lock(&lock);
        writeToBuffer(i);
        pthread_mutex_unlock(&lock);
        printBuffer();
        sem_post(&semaphore);
    }
    cout<<endl;
}

void* consumer1(void * arg)
{
    while(1)
    {
        pthread_mutex_lock(&mut);
        if(global%2==0)
        {
            sem_wait(&semaphore);
            pthread_mutex_lock(&lock);
            Node* temp = getBufferFront();
            pthread_mutex_unlock(&lock);  
            if(temp)
                cout<<"data consumed by consumer1="<<temp->data<<endl;
            else cout<<"NULL"<<endl;
            printBuffer();
            delete(temp);
            cout<<"global="<<global<<endl;  
            global++;
            pthread_cond_signal(&cond);
        }
        else
        {
            pthread_cond_wait(&cond,&mut);
        }
        pthread_mutex_unlock(&mut);
    }

}

void* consumer2(void* arg)
{

    while(1)
    {
        pthread_mutex_lock(&mut);
        if(global%2==1)
        {
            sem_wait(&semaphore);
            pthread_mutex_lock(&lock);
            Node* temp = getBufferFront();
            pthread_mutex_unlock(&lock);  
            if(temp)
                cout<<"data consumed by consumer2="<<temp->data<<endl;
            else cout<<"NULL"<<endl;
            printBuffer();
            delete(temp);
            cout<<"global="<<global<<endl;  
            global++;
            pthread_cond_signal(&cond);
        }
        else
        {
            pthread_cond_wait(&cond,&mut);
        }
        pthread_mutex_unlock(&mut);
    }
}

int main()
{
    pthread_t  th1,th2,th3;


    sem_init(&semaphore,0,0);
    sem_init(&sem2,0,0);
    if (pthread_mutex_init(&mut, NULL) != 0)
    {
        cout<<" mutex init has failed"<<endl;
        return 1;
    }
    if (pthread_mutex_init(&lock, NULL) != 0)
    {
        cout<<" mutex init has failed"<<endl;
        return 1;
    }


    buffer=0;


    pthread_create(&th1,0,producer,0);
    pthread_create(&th2,0,consumer1,0);
    pthread_create(&th3,0,consumer2,0);
    pthread_join(th1,0);
    pthread_join(th2,0);
    pthread_join(th3,0);
}

He told you have to use only 1 of the synchronization techniques. I wonder how to do. I tested with the later one. It 1st completes all producer work before transferring to consumer. But consumer do the work one after another. Can I get a better code? Some people opine that dividing task equally is not right thing to do. But I wish to know if I had to divide tasks equally then what would be the solution.

Sandeep
  • 17
  • 1
  • 6

0 Answers0