Make thread loop for 5 iterations; pthreads, mutex, and semaphors - c++

I have this code in an example for my class, and the instructions from the teacher say to "make each thread loop for 5 iterations". I am confused as to how to do that, wtih this code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <sys/utsname.h>
/* Symbolic Constants*/
#define NUM_THREADS 4
#define BUFFER_SIZE 10
/* Semaphore and Mutex lock */
sem_t cEmpty;
sem_t cFull;
pthread_mutex_t mutex;
/* Threads */
pthread_t tid; /* Thread ID */
pthread_attr_t attr; /* Thread attributes */
//prototypes
void *producer(void *param);
void *consumer(void *param);
int insert_item(int threadID);
int remove_item(int threadID);
void init();
/* Progress Counter and Thread IDs*/
int counter, pthreadID=0, cthreadID=0;
int main()
{
/* Variables */
int c1;
/* Perform initialization */
init();
/* Create the producer threads */
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid, &attr, producer, NULL);
}
/* Create the consumer threads */
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid, &attr, consumer, NULL);
}
/* Ending it */
sleep(2);
printf("All threads are done.\n");
/* Destroy the mutex and semaphors */
pthread_mutex_destroy(&mutex);
sem_destroy(&cEmpty);
sem_destroy(&cFull);
printf("Resources cleaned up.\n");
exit(0);
}
void init()
{
pthread_mutex_init(&mutex, NULL); /* Initialize mutex lock */
pthread_attr_init(&attr); /* Initialize pthread attributes to default */
sem_init(&cFull, 0, 0); /* Initialize full semaphore */
sem_init(&cEmpty, 0, BUFFER_SIZE); /* Initialize empty semaphore */
counter = 0; /* Initialize global counter */
}
void *producer(void *param)
{
int x;
for(x=0; x<5;)
{
sleep(1);
sem_wait(&cEmpty); /* Lock empty semaphore if not zero */
pthread_mutex_lock(&mutex);
if(insert_item(pthreadID))
{
fprintf(stderr, "Producer error.");
}
else
{
pthreadID++;
x++;
}
pthread_mutex_unlock(&mutex);
sem_post(&cFull); /* Increment semaphore for # of full */
}
return 0;
}
void *consumer(void *param)
{
int y;
for(y=0; y<5;)
{
sleep(1);
sem_wait(&cFull); /* Lock empty semaphore if not zero */
pthread_mutex_lock(&mutex);
if(remove_item(cthreadID))
{
fprintf(stderr, "Consumer error.");
}
else
{
cthreadID++;
y++;
}
pthread_mutex_unlock(&mutex);
sem_post(&cEmpty); /* Increments semaphore for # of empty */
}
return 0;
}
int insert_item(int threadID)
{
if(counter < BUFFER_SIZE) /* Buffer has space */
{
counter++;
printf("Producer %d inserted a cookie. Total:%d\n", threadID, counter);
return 0;
}
else /* Buffer full */
{
return -1;
}
}
int remove_item(int threadID)
{
if(counter > 0) /* Buffer has something in it */
{
counter--;
printf("Consumer %d removed a cookie. Total:%d\n", threadID, counter);
return 0;
}
else /* Buffer empty */
{
return -1;
}
}
Anyone have any idea of where I add my for loop to "make each thread loop for 5 iterations"? Thank you so much in advanced.
UPDATE: I changed the while(1) to a for loop with 5 iterations, but I still cant get the messages from the insert_item and remove_item functions to print 5 times, the only print once. Anyone know how I can get it to print 5 times?

The problem was that at the end of main, I call sleep(2). This is not enough time for all of the threads to print their output. I was also not passing the right index to my add_item and remove_item functions. In addition, I needed a join command for all of the threads rather than the sleep command, and the join command ensures that all of the threads finish before the program exits. Here is the updated and corrected code. Hope this helps someone trying to do something similar!
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <sys/utsname.h>
// Symbolic Constants
#define NUM_THREADS 4
#define BUFFER_SIZE 10
// Semaphore and Mutex lock
sem_t cEmpty;
sem_t cFull;
pthread_mutex_t mutex;
// Threads
pthread_t tid[NUM_THREADS]; //Thread ID
pthread_t tid2[NUM_THREADS]; //Thread ID
pthread_attr_t attr; //Thread attributes
//prototypes
void *producer(void *param);
void *consumer(void *param);
int insert_item(long threadID);
int remove_item(long threadID);
void init();
//Progress Counter and Thread IDs
int counter=0;
int main()
{
//Variables
long c1;
//Perform initialization
init();
//Create the producer threads
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid[c1], &attr, producer, (void *)c1);
pthread_create(&tid2[c1], &attr, consumer, (void *)c1);
}
//Ending it
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_join(tid[c1], NULL);
pthread_join(tid2[c1],NULL);
}
printf("All threads are done.\n");
//Destroy the mutex and semaphors
pthread_mutex_destroy(&mutex);
sem_destroy(&cEmpty);
sem_destroy(&cFull);
printf("Resources cleaned up.\n");
exit(0);
}
//This function performs initialization
void init()
{
pthread_mutex_init(&mutex, NULL); //Initialize mutex lock
pthread_attr_init(&attr); //Initialize pthread attributes to default
sem_init(&cFull, 0, 0); //Initialize full semaphore
sem_init(&cEmpty, 0, BUFFER_SIZE); //Initialize empty semaphore
counter = 0; //Initialize global counter
}
//This function creates the producer thread
void *producer(void *param)
{
long index = (long)param;
for(int x = 0; x<5; x++)
{
sleep(1);
sem_wait(&cEmpty); //Lock empty semaphore if not zero
pthread_mutex_lock(&mutex);
//check to see if item inserted correctly; print error on fail
if(insert_item(index))
{
fprintf(stderr, "Producer error.");
}
pthread_mutex_unlock(&mutex);
sem_post(&cFull); //Increment semaphore for # of full
}
pthread_exit(NULL);
return 0;
}
//This function created the consumer thread
void *consumer(void *param)
{
long index = (long)param;
for(int x = 0; x<5; x++)
{
sleep(1);
sem_wait(&cFull); //Lock empty semaphore if not zero
pthread_mutex_lock(&mutex);
//print error if cookie not decremented correctly
if(remove_item(index))
{
fprintf(stderr, "Consumer error.");
}
pthread_mutex_unlock(&mutex);
sem_post(&cEmpty); //Increments semaphore for # of empty
}
pthread_exit(NULL);
return 0;
}
//Insert item function to increment the cookie count and print thread message
int insert_item(long threadID)
{
if(counter < BUFFER_SIZE) //Buffer has space
{
counter++;
printf("Producer %ld inserted a cookie. Total:%d\n", threadID, counter);
return 0;
}
else //Buffer full
{
return -1;
}
}
//Remove item function to decrement the cookie count and print thread message
int remove_item(long threadID)
{
if(counter > 0) //Buffer has something in it
{
counter--;
printf("Consumer %ld removed a cookie. Total:%d\n", threadID, counter);
return 0;
}
else //Buffer empty
{
return -1;
}
}

Related

How to suspend and resume a POSIX thread in C++?

As I came to know creating and terminating thread abruptly
using pthread_kill() everytime is not a good way to do, so I am going
with suspend and resume method for a thread using thread1.suspend() and
thread1.resume(), whenever needed. How to do/implement this?
Take below LED blinking code for reference. During thread1.start() creating thread with suspended = false; is continuing as it is stuck in a while loop.
Calling thread1.suspend() has no effect.
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
bool suspended;
int fd;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;
void start() {
suspended = false;
pthread_create(&threadID, NULL, led_Flash, (void*)this );
}
PThread(int fd1) { this->fd=fd1; }
~PThread() { }
void suspend() {
pthread_mutex_lock(&m_SuspendMutex);
suspended = true;
printf("suspended\n");
do {
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
} while (suspended);
pthread_mutex_unlock(&m_SuspendMutex);
}
void resume() {
/* The shared state 'suspended' must be updated with the mutex held. */
pthread_mutex_lock(&m_SuspendMutex);
suspended = false;
printf("Resumed\n");
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
};
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int ret=0;
int fd= pt->fd;
while(pt->suspended == false)
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
return NULL;
}
int main()
{
int fd1=1,fd2=2, fd3=3;
class PThread redLED(fd1);
class PThread amberLED(fd2);
class PThread greenLED(fd3);
redLED.start();
amberLED.start();
greenLED.start();
sleep(1);
redLED.suspend();
return 0;
}
Could some body help me, please?
After a little modification of above code , it seems working . Thanks guy for pointing out issues on above code, the changes are as follow.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<iostream>
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
volatile int suspended;
int fd;
pthread_mutex_t lock;
PThread(int fd1)
{
this->fd=fd1;
this->suspended =1; //Initial state: suspend blinking untill resume call
pthread_mutex_init(&this->lock,NULL);
pthread_create(&this->threadID, NULL, led_Flash, (void*)this );
}
~PThread()
{
pthread_join(this->threadID , NULL);
pthread_mutex_destroy(&this->lock);
}
void suspendBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 1;
pthread_mutex_unlock(&this->lock);
}
void resumeBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 0;
pthread_mutex_unlock(&this->lock);
}
};
void gpio_write(int fd, int value)
{
if(value!=0)
printf("%d: on\n", fd);
else
printf("%d: off\n", fd);
}
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int fd= pt->fd;
while(1)
{
if(!(pt->suspended))
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
}
return NULL;
}
int main()
{
//Create threads with Initial state: suspend/stop blinking untill resume call
class PThread redLED(1);
class PThread amberLED(2);
class PThread greenLED(3);
// Start blinking
redLED.resumeBlink();
amberLED.resumeBlink();
greenLED.resumeBlink();
sleep(5);
// suspend/stop blinking
amberLED.suspendBlink();
sleep(5);
redLED.suspendBlink();
sleep(5);
amberLED.suspendBlink();
sleep(5);
redLED.resumeBlink();
pthread_exit(NULL);
return 0;
}

Integrating pthread_create() and pthread_join() in the same loop

I am new to multi-threaded programming and I am following this tutorial. In the tutorial, there is a simple example showing how to use pthread_create() and pthread_join(). My question: why can we not put pthread_join() in the same loop as pthread_create()?
Code for reference:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREADS 2
/* create thread argument struct for thr_func() */
typedef struct _thread_data_t {
int tid;
double stuff;
} thread_data_t;
/* thread function */
void *thr_func(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
printf("hello from thr_func, thread id: %d\n", data->tid);
pthread_exit(NULL);
}
int main(int argc, char **argv) {
pthread_t thr[NUM_THREADS];
int i, rc;
/* create a thread_data_t argument array */
thread_data_t thr_data[NUM_THREADS];
/* create threads */
for (i = 0; i < NUM_THREADS; ++i) {
thr_data[i].tid = i;
if ((rc = pthread_create(&thr[i], NULL, thr_func, &thr_data[i]))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc);
return EXIT_FAILURE;
}
}
/* block until all threads complete */
for (i = 0; i < NUM_THREADS; ++i) {
pthread_join(thr[i], NULL);
}
return EXIT_SUCCESS;
}
I figured it out. For other users with same question, I am writing below the answer.
If we put the pthread_join() in the same loop with pthread_create(), the calling thread i.e. main() will wait for the thread 0 to finish its work before creating the thread 1. This would force the threads to execute sequentially, not in parallel. Thus it would kill the purpose of multi-threading.

Call join child pthread in main function

I have the test code:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_t th_worker, th_worker2;
void * worker2(void *data) {
for(int i = 0; i< 1000000; i++){
printf("thread for worker2----%d\n", i);
usleep(500);
}
}
void * worker(void *data){
pthread_create(&th_worker2, NULL, worker2, data);
for(int i = 0; i< 100; i++){
printf("thread for worker-----%d\n", i);
usleep(500);
}
}
void join(pthread_t _th){
pthread_join(_th, NULL);
}
In main() function, If I call join(the_worker2):
int main() {
char* str = "hello thread";
pthread_create(&th_worker, NULL, worker, (void*) str);
/* problem in here */
join(th_worker2);
return 1;
}
--> Segment Fault error
Else, i call:
join(the_worker);
join(th_worker2);
---> OK
Why have segment fault error in above case?
Thanks for help !!!
If you posted all your code, you have a race condition.
main is synchronized with the start of worker but not worker2.
That is, main is trying to join th_worker2 before worker has had a chance to invoke pthread_create and set up th_worker2 with a valid [non-null] value.
So, th_worker2 will be invalid until the second pthread_create completes, but that's already too late for main. It has already fetched th_worker2, which has a NULL value and main will segfault.
When you add the join for th_worker, it works because it guarantees synchronization and no race condition.
To achieve this guarantee without the join, have main do:
int
main()
{
char *str = "hello thread";
pthread_create(&th_worker, NULL, worker, (void *) str);
// give worker enough time to properly start worker2
while (! th_worker2)
usleep(100);
/* problem in here */
join(th_worker2);
return 1;
}
An even better way to do this is to add an extra variable. With this, the first loop is not needed [but I've left it in]:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int worker_running;
pthread_t th_worker;
int worker2_running;
pthread_t th_worker2;
void *
worker2(void *data)
{
// tell main we're fully functional
worker2_running = 1;
for (int i = 0; i < 1000000; i++) {
printf("thread for worker2----%d\n", i);
usleep(500);
}
return NULL;
}
void *
worker(void *data)
{
// tell main we're fully functional
worker_running = 1;
pthread_create(&th_worker2, NULL, worker2, data);
for (int i = 0; i < 100; i++) {
printf("thread for worker-----%d\n", i);
usleep(500);
}
return NULL;
}
void
join(pthread_t _th)
{
pthread_join(_th, NULL);
}
int
main()
{
char *str = "hello thread";
pthread_create(&th_worker, NULL, worker, (void *) str);
// give worker enough time to properly start worker2
// NOTE: this not necessarily needed as loop below is better
while (! th_worker2)
usleep(100);
// give worker2 enough time to completely start
while (! worker2_running)
usleep(100);
/* problem in here (not anymore!) */
join(th_worker2);
return 1;
}

Idea Behind Recursive Mutex Lock

I'm working on a school lab and we are instructed to create a recursive mutex lock for a counting program. I've written some code (which doesn't work), but I think that this is mostly because I do not understand the real idea behind using a recursive mutex lock. Could anyone elaborate what a recursive mutex lock should do/look like?
General Note: I'm not asking for an answer, just some clarification as to what recursive mutex lock should do.
Also, if anyone is curious, here is the code required for this. The code that I am editing/implementing is the recmutex.c.
recmutex.h
#include <pthread.h>
/*
* The recursive_mutex structure.
*/
struct recursive_mutex {
pthread_cond_t cond;
pthread_mutex_t mutex; //a non-recursive pthread mutex
pthread_t owner;
unsigned int count;
unsigned int wait_count;
};
typedef struct recursive_mutex recursive_mutex_t;
/* Initialize the recursive mutex object.
*Return a non-zero integer if errors occur.
*/
int recursive_mutex_init (recursive_mutex_t *mu);
/* Destroy the recursive mutex object.
*Return a non-zero integer if errors occur.
*/
int recursive_mutex_destroy (recursive_mutex_t *mu);
/* The recursive mutex object referenced by mu shall be
locked by calling pthread_mutex_lock(). When a thread
successfully acquires a mutex for the first time,
the lock count shall be set to one and successfully return.
Every time a thread relocks this mutex, the lock count
shall be incremented by one and return success immediately.
And any other calling thread can only wait on the conditional
variable until being waked up. Return a non-zero integer if errors occur.
*/
int recursive_mutex_lock (recursive_mutex_t *mu);
/* The recursive_mutex_unlock() function shall release the
recursive mutex object referenced by mu. Each time the owner
thread unlocks the mutex, the lock count shall be decremented by one.
When the lock count reaches zero, the mutex shall become available
for other threads to acquire. If a thread attempts to unlock a
mutex that it has not locked or a mutex which is unlocked,
an error shall be returned. Return a non-zero integer if errors occur.
*/
int recursive_mutex_unlock (recursive_mutex_t *mu);
recmutex.c: contains the functions for the recursive mutex
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include "recmutex.h"
int recursive_mutex_init (recursive_mutex_t *mu){
int err;
err = pthread_mutex_init(&mu->mutex, NULL);
if(err != 0){
perror("pthread_mutex_init");
return -1;
}else{
return 0;
}
return 0;
}
int recursive_mutex_destroy (recursive_mutex_t *mu){
int err;
err = pthread_mutex_destroy(&mu->mutex);
if(err != 0){
perror("pthread_mutex_destroy");
return -1;
}else{
return 1;
}
return 0;
}
int recursive_mutex_lock (recursive_mutex_t *mu){
if(mutex_lock_count == 0){
pthread_mutex_lock(&mu->mutex);
mu->count++;
mu->owner = pthread_self();
printf("%s", mu->owner);
return 0;
}else if(mutex_lock_count > 0){
pthread_mutex_lock(&mu->mutex);
mu->count++;
mu->owner = pthread_self();
return 0;
}else{
perror("Counter decremented incorrectly");
return -1;
}
}
int recursive_mutex_unlock (recursive_mutex_t *mu){
if(mutex_lock_count <= 0){
printf("Nothing to unlock");
return -1;
}else{
mutex_lock_count--;
pthread_mutex_unlock(&mu->mutex);
return 0;
}
}
count_recursive.cc: The counting program mentioned above. Uses the recmutex functions.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include "recmutex.h"
//argument structure for the thread
typedef struct _arg_{
int n1;
int n2;
int ntimes;
}Arg;
int count; //global counter
recursive_mutex_t mutex; //the recursive mutex
void do_inc(int n){
int ret;
if(n == 0){
return;
}else{
int c;
ret = recursive_mutex_lock(&mutex);
assert(ret == 0);
c = count;
c = c + 1;
count = c;
do_inc(n - 1);
ret = recursive_mutex_unlock(&mutex);
assert(ret == 0);
}
}
/* Counter increment function. It will increase the counter by n1 * n2 * ntimes. */
void inc(void *arg){
Arg * a = (Arg *)arg;
for(int i = 0; i < a->n1; i++){
for(int j = 0; j < a->n2; j++){
do_inc(a->ntimes);
}
}
}
int isPositiveInteger (const char * s)
{
if (s == NULL || *s == '\0' || isspace(*s))
return 0;
char * p;
int ret = strtol (s, &p, 10);
if(*p == '\0' && ret > 0)
return 1;
else
return 0;
}
int test1(char **argv){
printf("==========================Test 1===========================\n");
int ret;
//Get the arguments from the command line.
int num_threads = atoi(argv[1]); //The number of threads to be created.
int n1 = atoi(argv[2]); //The outer loop count of the inc function.
int n2 = atoi(argv[3]); //The inner loop count of the inc function.
int ntimes = atoi(argv[4]); //The number of increments to be performed in the do_inc function.
pthread_t *th_pool = new pthread_t[num_threads];
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
ret = recursive_mutex_init(&mutex);
assert(ret == 0);
printf("Start Test. Final count should be %d\n", num_threads * n1 * n2 * ntimes );
// Create threads
for(int i = 0; i < num_threads; i++){
Arg *arg = (Arg *)malloc(sizeof(Arg));
arg->n1 = n1;
arg->n2 = n2;
arg->ntimes = ntimes;
ret = pthread_create(&(th_pool[i]), &attr, (void * (*)(void *)) inc, (void *)arg);
assert(ret == 0);
}
// Wait until threads are done
for(int i = 0; i < num_threads; i++){
ret = pthread_join(th_pool[i], NULL);
assert(ret == 0);
}
if ( count != num_threads * n1 * n2 * ntimes) {
printf("\n****** Error. Final count is %d\n", count );
printf("****** It should be %d\n", num_threads * n1 * n2 * ntimes );
}
else {
printf("\n>>>>>> O.K. Final count is %d\n", count );
}
ret = recursive_mutex_destroy(&mutex);
assert(ret == 0);
delete [] th_pool;
return 0;
}
int foo(){
int ret;
printf("Function foo\n");
ret = recursive_mutex_unlock(&mutex);
assert(ret != 0);
return ret;
}
//test a thread call unlock without actually holding it.
int test2(){
int ret;
printf("\n==========================Test 2==========================\n");
pthread_t th;
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
ret = recursive_mutex_init(&mutex);
ret = pthread_create(&th, &attr, (void * (*)(void *))foo, NULL);
printf("Waiting for thread to finish\n");
ret = pthread_join(th, NULL);
assert(ret == 0);
return 0;
}
int main( int argc, char ** argv )
{
int ret;
count = 0;
if( argc != 5 ) {
printf("You must enter 4 arguments. \nUsage: ./count_recursive num_threads n1 n2 ntimes\n");
return -1;
}
if(isPositiveInteger(argv[1]) != 1 || isPositiveInteger(argv[2]) != 1 || isPositiveInteger(argv[3]) != 1 || isPositiveInteger(argv[4]) != 1 ){
printf("All the 4 arguments must be positive integers\n");
return -1;
}
test1(argv);
test2();
return 0;
}
The idea of a recursive mutex is that it can be successfully relocked by the thread that is currently holding the lock. For example:
if I had some mutexes like this (this is pseudocode):
mutex l;
recursive_mutex r;
In a single thread if I did this:
l.lock();
l.lock(); // this would hang the thread.
but
r.lock();
r.lock();
r.lock(); // this would all pass though with no issue.
In implimenting a recursive mutex you need to check what threadId has locked it, if it was locked, and if it matches the current thread id, return success.
The point of a recursive mutex, is to let you write this:
recursive_mutext_t rmutex;
void foo(...) {
recursive_lock_lock(&rmutex);
...
recursive_lock_unlock(&rmutex);
}
void bar(...) {
recursive_lock_lock(&rmutex);
...
foo(...);
...
recursive_lock_unlock(&rmutex);
}
void baz(...) {
...
foo(...);
...
}
The function foo() needs the mutex to be locked, but you want to be able to call it either from bar() where the same mutex is already locked, or from baz() where the mutex is not locked. If you used an ordinary mutex(), the thread would self-deadlock when foo() is called from bar() because the ordinary mutex lock() function will not return until the mutex is unlocked, and there's no other thread that will unlock it.
Your recursive_mutex_lock() needs to distinguish these cases; (1) The mutex is not locked, (2) the mutex is already locked, but the calling thread is the owner, and (3) the mutex is already locked by some other thread.
Case (3) needs to block the calling thread until the owner completely unlocks the mutex. At that point, it then converts to case (1). Here's a hint: Handle case (3) with a condition variable. That is to say, when the calling thread is not the owner, the calling thread should do a pthread_condition_wait(...) call.

vanilla and chokolate cake producing and consuming by waiter in c++ using semaphore mutex in ubuntu

In my problem two chef, chef x will produce chokolate cake, chef y will produce vanilla cake. There are 5 slots queue0 to put cakes. When slots are full they will take break. Chef z will take cake from this slots and puts vanilla cake in queue1 and chokolate cake in queue2. Waiter 1 takes cake from queue1 and waiter 2 take cakes from queue2. When queue0 is not full chef x and chef y starts making cake. I wrote a code. But it shows that chef y can produce 4 vanilla cake then the code stuck and no further output is showing.
Here is my Code
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include<semaphore.h>
//#include </usr/include/semaphore.h>
// for sleep
#include <unistd.h>
#define BUFF_SIZE 5 /* total number of slots */
typedef struct //Producing queue
{
char buf1[BUFF_SIZE]; /* shared var */
int in1; /* buf[in%BUFF_SIZE] is the first empty slot */
int out1; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
// use correct type here
pthread_mutex_t mutex; /* enforce mutual exclusion to shared data */
} sbuf_t1;
typedef struct //Chokolate Cake queue
{
char buf2[BUFF_SIZE]; /* shared var */
int in2; /* buf[in%BUFF_SIZE] is the first empty slot */
int out2; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
// use correct type here
pthread_mutex_t mutex; /* enforce mutual exclusion to shared data */
} sbuf_t2;
typedef struct //Vanilla Cake queue
{
char buf3[BUFF_SIZE]; /* shared var */
int in3; /* buf[in%BUFF_SIZE] is the first empty slot */
int out3; /* buf[out%BUFF_SIZE] is the first full slot */
sem_t full; /* keep track of the number of full spots */
sem_t empty; /* keep track of the number of empty spots */
// use correct type here
pthread_mutex_t mutex; /* enforce mutual exclusion to shared data */
} sbuf_t3;
sbuf_t1 shared1;
sbuf_t2 shared2;
sbuf_t3 shared3;
void *Producer1(void *arg)
{
int i, index;
char item;
index = (int)arg;
for(i=0; i<10; ++i)
{
sem_wait(&shared1.empty);
pthread_mutex_lock(&shared1.mutex);
sleep(1);
shared1.buf1[shared1.in1] = 'C';
shared1.in1 = (shared1.in1+1)%BUFF_SIZE;
printf("[P%d] Producing Chokolate Cake...\n", index);
fflush(stdout);
/* Release the buffer */
pthread_mutex_unlock(&shared1.mutex);
/* Increment the number of full slots */
sem_post(&shared1.full);
//if (i % 2 == 1) sleep(1);
}
return NULL;
}
void *Producer2(void *arg)
{
int i, index;
char item;
index = (int)arg;
for(i=0; i<10; ++i)
{
item = i;
sem_wait(&shared1.empty);
pthread_mutex_lock(&shared1.mutex);
sleep(1);
shared1.buf1[shared1.in1] = 'V';
shared1.in1 = (shared1.in1+1)%BUFF_SIZE;
printf("[P%d] Producing Vanilla Cake...\n", index);
fflush(stdout);
/* Release the buffer */
pthread_mutex_unlock(&shared1.mutex);
/* Increment the number of full slots */
sem_post(&shared1.full);
//if (i % 2 == 1) sleep(1);
}
return NULL;
}
void *Chef_Z(void *arg)
{
int i, index;
char item;
index = (int)arg;
for (i=10; i > 0; i--) {
sem_wait(&shared1.full);
pthread_mutex_lock(&shared1.mutex);
sleep(1);
item=shared1.buf1[shared1.out1];
if(item == 'C') // Chokolate Cake queue
{
sem_wait(&shared2.full);
pthread_mutex_lock(&shared2.mutex);
shared2.buf2[shared2.in2]=item;
shared2.in2 = (shared2.in2+1)%BUFF_SIZE;
printf("[C_Z] Consuming Chokolate Cake and stored it in Chokolate queue ...\n");
pthread_mutex_unlock(&shared2.mutex);
/* Increment the number of full slots */
sem_post(&shared2.empty);
}
else if(item == 'V') // Vanilla Cake queue
{
sem_wait(&shared3.full);
pthread_mutex_lock(&shared3.mutex);
shared3.buf3[shared3.in3]=item;
shared3.in3 = (shared3.in3+1)%BUFF_SIZE;
printf("[C_Z] Consuming Vanilla Cake and stored it in Vanilla queue ...\n");
pthread_mutex_unlock(&shared3.mutex);
/* Increment the number of full slots */
sem_post(&shared3.empty);
}
shared1.out1 = (shared1.out1+1)%BUFF_SIZE;
fflush(stdout);
/* Release the buffer */
pthread_mutex_unlock(&shared1.mutex);
/* Increment the number of full slots */
sem_post(&shared1.empty);
/* Interleave producer and consumer execution */
//if (i % 2 == 1) sleep(1);
}
return NULL;
}
void *Waiter1(void *arg) //Chokolate cake waiter
{
int i, index;
char item;
index = (int)arg;
for (i=10; i > 0; i--) {
sem_wait(&shared2.full);
pthread_mutex_lock(&shared2.mutex);
sleep(1);
item=shared2.buf2[shared2.out2];
shared2.out2 = (shared2.out2+1)%BUFF_SIZE;
printf("[W%d] Consuming Chokolate Cake ...\n", index);
fflush(stdout);
/* Release the buffer */
pthread_mutex_unlock(&shared2.mutex);
/* Increment the number of full slots */
sem_post(&shared2.empty);
/* Interleave producer and consumer execution */
//if (i % 2 == 1) sleep(1);
}
return NULL;
}
void *Waiter2(void *arg) // Vanilla cake waiter
{
int i, index;
char item;
index = (int)arg;
for (i=10; i > 0; i--) {
sem_wait(&shared3.full);
pthread_mutex_lock(&shared3.mutex);
sleep(1);
item=shared3.buf3[shared3.out3];
shared3.out3 = (shared3.out3+1)%BUFF_SIZE;
printf("[W%d] Consuming Vanilla Cake ...\n", index);
fflush(stdout);
/* Release the buffer */
pthread_mutex_unlock(&shared3.mutex);
/* Increment the number of full slots */
sem_post(&shared3.empty);
/* Interleave producer and consumer execution */
//if (i % 2 == 1) sleep(1);
}
return NULL;
}
int main()
{
//pthread_t idP, idC;
pthread_t thread1,thread2,thread3,thread4,thread5;
int index;
void *producer1End;
void *producer2End;
void *chef_zEnd;
void *waiter1End;
void *waiter2End;
sem_init(&shared1.full, 0, 0);
sem_init(&shared1.empty, 0, BUFF_SIZE);
pthread_mutex_init(&shared1.mutex, NULL);
sem_init(&shared2.full, 0, 0);
sem_init(&shared2.empty, 0, BUFF_SIZE);
pthread_mutex_init(&shared2.mutex, NULL);
sem_init(&shared3.full, 0, 0);
sem_init(&shared3.empty, 0, BUFF_SIZE);
pthread_mutex_init(&shared3.mutex, NULL);
pthread_create(&thread1, NULL, Producer1, (void*)1 );
pthread_create(&thread2, NULL, Producer2, (void*)2 );
pthread_create(&thread3, NULL, Chef_Z, (void*)1 );
pthread_create(&thread4, NULL, Waiter1, (void*)1);
pthread_create(&thread5, NULL, Waiter2, (void*)2);
pthread_join(thread1,&producer1End);
pthread_join(thread2,&producer2End);
pthread_join(thread3,&chef_zEnd);
pthread_join(thread4,&waiter1End);
pthread_join(thread5,&waiter2End);
pthread_exit(NULL);
}