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.