Reputation: 145
I am trying to understand semaphores and cannot solve the issue with my implementation with the constraints given. I am using 6 threads with the constraints: 0,1,2 complete work ASAP; 3 must wait for 0 and 1; 4 must wait for 1 and 2 before starting; 5 should wait for 0 and 2. I decided to use switch statements for this particular problem but can't seem to understand where I went wrong.
#include <iostream>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include "sem.h"
#include <cstdlib>
#define THREAD_COUNT 6
using namespace std;
extern sim_semaphore create_sim_sem(int) ;
extern void wait_sem (sim_semaphore) ;
extern void signal_sem (sim_semaphore) ;
pthread_mutex_t stdoutLock ;
int thrds_finished ;
// global sync variables
sim_semaphore support_ready[THREAD_COUNT] ;
sim_semaphore finished ;
/* These are global variable to represent threads created
dynamically. */
pthread_t thr[THREAD_COUNT] ;
/* This is included to facilitate adding random delays in the code
-- as a debugging aid. */
extern long random(void);
int checking = 0 ;
/* A data type - a struct (class) with an int field to represent
a thread ID. */
struct threadIdType
{
int id ;
};
void init()
{
if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
{ cout << "MUTEX INITIALIZATION FAILURE!" << endl ;
exit(-1) ;}
thrds_finished = 0 ;
finished = create_sim_sem(0) ;
int count ;
for (count = 0; count < THREAD_COUNT ; count++)
{
support_ready[count] = create_sim_sem(0) ;
}
/* This initializes a random number generator */
srandom(time((time_t *) 0));
}
void rand_delay(int max)
{
int m_delay, j ;
m_delay = (int) random()%max ;
for (j=0; j<m_delay; j++) sched_yield();
}
void childMessage (int ID)
{
pthread_mutex_lock(&stdoutLock) ;
cout << "Child # " << ID
<< " has completed its assignment.\n" ;
pthread_mutex_unlock(&stdoutLock) ;
}
void * child(void * idPtr)
{
int me = ((threadIdType *) (idPtr))->id, temp ;
rand_delay(100) ;
// wait constraints
switch(me)
{
case 0: break ; // thread 0 just 'goes'
case 1: break ; // thread 1 just 'goes'
case 2: break ; // thread 2 just 'goes'
case 3: wait_sem (support_ready[0]) ;
wait_sem (support_ready[1]) ; // thread 3 waits for both 0 and 1
break ;
case 4: wait_sem (support_ready[1]) ;
wait_sem (support_ready[2]) ; // thread 4 waits for both 1 and 2
break ;
case 5: wait_sem (support_ready[0]) ;
wait_sem (support_ready[2]) ; // thread 5 waits for both 0 and 2
break ;
default: pthread_mutex_lock(&stdoutLock) ;
cout << "\n\nBAD VALUE TO CASE STATMENT!!\n\n" ;
pthread_mutex_unlock(&stdoutLock) ;
exit (-1); break ;
}
rand_delay(1000) ;
/* Next increment thrds_finished - to keep track
of how many child processes have finished their
tasks. */
/* Here put code you may need for protecting
thrds_finished. */
/* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */
/* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */
/* This code increments thrds_finished in a way
that magnifies the problem if the critical section
problem is not solved correctly. Of course,
do not change this part of the code. */
temp = thrds_finished ;
rand_delay(1000) ;
temp++ ;
rand_delay(1000) ;
thrds_finished = temp ;
/* Here put additional code you may need for protecting
thrds_finished. */
/* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */
/* HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH */
/* Announce completion of the assignment. */
childMessage(me) ;
switch(me)
{
case 0: signal_sem(support_ready[0]);
signal_sem(support_ready[0]); // thread 0 signals for threads 3 5
break ;
case 1: signal_sem(support_ready[1]) ; // thread 1 signals for 3 4
signal_sem(support_ready[1]) ;
break ;
case 2: signal_sem(support_ready[2]) ; // thread 2 signals for 4 5
signal_sem(support_ready[2]) ;
break;
case 3: break;
case 4: break;
case 5: signal_sem (finished); break; // thread 5 signals to the mother
default: pthread_mutex_lock(&stdoutLock) ;
cout << "\n\nBAD VALUE TO CASE STATMENT!!\n\n" ;
pthread_mutex_unlock(&stdoutLock) ;
exit (-1); break ;
}
pthread_exit ((void *)0) ;
}
// spawn child threads and waits for them to finish
void mother()
{
int i;
threadIdType * idPtr ;
/* Create child threads numbered 1 through 8. */
pthread_mutex_lock(&stdoutLock) ;
cout << "Mother Begins Spawning Threads.\n" << endl ;
pthread_mutex_unlock(&stdoutLock) ;
for (i = 0; i < THREAD_COUNT ; i++)
{
idPtr = new threadIdType ; /* allocate memory for struct */
idPtr->id = i ; /* records current index as the child's ID */
if ( 0!=pthread_create(&thr[i], NULL, child, (void *) idPtr) )
{ pthread_mutex_lock(&stdoutLock) ; /* 'error out' code here */
cout << "THREAD CREATION FAILURE!" << endl ;
pthread_mutex_unlock(&stdoutLock) ;
exit(-1) ; }
if (0!=pthread_detach(thr[i]))
{ pthread_mutex_lock(&stdoutLock) ;/* 'error out' code here */
cout << "THREAD DETACHMENT FAILURE!" << endl ;
pthread_mutex_unlock(&stdoutLock) ;
exit(-1) ;}
}
rand_delay(3000) ; /* Simulate whatever may delay the mother thread */
pthread_mutex_lock(&stdoutLock) ;
cout << "Mother Finishes Spawning Threads.\n" << endl ;
pthread_mutex_unlock(&stdoutLock) ;
/* Some synchronization code is needed here to make the mother
behave correctly - she is not supposed to exit until after
all the children have finished their tasks. */
wait_sem (finished) ;
pthread_mutex_lock(&stdoutLock) ;
cout << "\nAll children have now reported that they finished.\n" ;
cout << "The value of the thrds_finished counter is: " ;
cout << thrds_finished << ".\n" ;
if (thrds_finished != THREAD_COUNT)
cout << "BAD COUNTER VALUE!! - Critical Section Problem Failure!!\n" ;
cout << "Mother exiting ... \n\n" ;
pthread_mutex_unlock(&stdoutLock) ;
return ;
}
int main()
{
cout << "\nWelcome to The Child Thread Workplace!\n\n" ;
/* This calls the function that performs initializations. */
init();
/* Execute the mother() function */
mother();
return 0 ;
}
This thread should send a signal to a mother function that spawns the child threads and waits for them to finish.
My issue here is that when I compile and run sometimes not all the threads show as completed and seem to be unsynced from the constraints given.
Upvotes: 0
Views: 258
Reputation: 340178
You haven't posted enough code for us to be able to fully diagnose what's wrong (for example, there's nothing in what you posted that indicates how you determine that threads have or have not completed). But from what you did post, it appears that at least one part of the problem is likely to be that Thread 5 only waits for a signal from 0 and 2 then signals "finished" regardless of whether other threads have gotten their signals, much less completed their work.
For example, threads 0, 2, and 5 can finish their work without threads 1, 3 or 4 ever getting run at all.
Upvotes: 1