I've a FIFO queue, producers and consumers which I try in different combinations which works except just this arrangement. I'm supposed to be able to run this with 3 Producers, 2 Consumers, 10 slots for the FIFO, and no semaphores to begin with, and then also make it with semaphores active.
#include <stdio.h>
#include "oslab_lowlevel_h.h"
int NextPrime( int );
#define FIFO_SIZE 10
/* Declare a structure to hold a producer's starting value,
* and an integer for the Producer-number (Producer 1, 2 or 3). */
struct Prod {
int startvalue;
int id;
};
unsigned int stack1[0x400]; /* Stack for thread 1 */
unsigned int stack2[0x400]; /* Stack for thread 2 */
unsigned int stack3[0x400]; /* Stack for thread 3 */
unsigned int stack4[0x400]; /* Stack for thread 4 */
unsigned int stack5[0x400]; /* Stack for thread 5 */
/* Declare variables for the First-In-First-Out Queue */
int Fifo[FIFO_SIZE]; /* Array holding FIFO queue data. */
int rdaddr; /* Next unread entry when reading from queue. */
int wraddr; /* Next free entry when writing into queue. */
/* Declaration of semaphore variables.
*/
int rdmutex = 1;
int wrmutex = 1;
int nrempty = FIFO_SIZE;
int nrfull = 0;
/*
* fatal_error
*
* Print a message, then stop execution.
* This function never returns; after printing
* the message, it enters an infinite loop.
*/
void fatal_error( char * msg)
{
printf( "\nFatal error: %s\n", msg );
while( 1 );
}
/*
* Sleep
*
* Delay execution by keeping the CPU busy for a while,
* counting down to zero.
*/
void Sleep (int n)
{
while (n--);
}
/*
* Signal
*
* Semaphore operation: add to semaphore,
* possibly allowing other threads to continue.
*/
void Signal( int *sem )
{
/* We must disable interrupts, since the operation
* *sem = *sem + 1
* will require several machine instructions on Nios2.
* If we have a timer-interrupt and a thread-switch
* somewhere in the middle of those machine instructions,
* the semaphore will be updated twice, or not at all, or
* in some other erroneous way.
*/
oslab_begin_critical_region();
*sem = *sem + 1;
oslab_end_critical_region();
}
/*
* Wait
*
* Sempahore operation: check semaphore, and
* wait if the semaphore value is zero or less.
*/
void Wait( int *sem )
{
/* Disable interrupts. */
oslab_begin_critical_region();
while ( *sem <= 0 )
{
/* If we should wait, enable interrupts again. */
oslab_end_critical_region();
//oslab_yield(); /* Perhaps we should yield here? */
/* Disable interrupts again before next iteration in loop. */
oslab_begin_critical_region();
}
/* We have waited long enough - the semaphore-value is now
* greater than zero. Decrease it. */
*sem = *sem - 1;
/* Enable interrupts again. */
oslab_end_critical_region();
}
/*
* PutFifo
*
* Insert an integer into the FIFO queue.
*/
void PutFifo( int tal )
{
//Wait (&nrempty); /* Wait for nrempty? */
//Wait (&wrmutex); /* Wait for wrmutex? */
Fifo[wraddr] = tal; /* Write to FIFO array. */
// printf("\nPutFifo: %d ", tal); /* Optional debug output */
// printf("\nwraddr = %d ", wraddr); /* Optional debug output. */
wraddr = wraddr + 1; /* Increase index into FIFO array,
to point to the next free position. */
/* Wrap around the index, if it has reached the end of the array. */
if (wraddr == FIFO_SIZE ) wraddr = 0;
//Signal (&wrmutex); /* Signal wrmutex? */
//Signal (&nrfull); /* Signal nrfull? */
}
/*
* GetFifo
*
* Extract the next integer from the FIFO queue.
*/
int GetFifo( void )
{
int retval; /* Declare temporary for return value. */
//Wait (&nrfull); /* Wait for nrfull? */
//Wait (&rdmutex); /* Wait for rdmutex? */
retval = Fifo[rdaddr]; /* Get value from FIFO array. */
// printf("\nGetFifo: %d ", retval); /* Optional debug output */
// printf("\nrdaddr = %d ", rdaddr); /* Optional debug output */
rdaddr = rdaddr + 1; /* Increase index into FIFO array,
to point to the next free position. */
/* Wrap around the index, if it has reached the end of the array. */
if (rdaddr == FIFO_SIZE ) rdaddr = 0;
//Signal (&rdmutex); /* Signal rdmutex? */
//Signal (&nrempty); /* Signal nrempty? */
return (retval); /* Return value fetched from FIFO. */
}
/*
* NextPrime
*
* Return the first prime number larger than the integer
* given as a parameter. The integer must be positive.
*
* *** NextPrime is outside the focus of this assignment. ***
* The definition of NextPrime can be found at the end of this file.
* The short declaration here is required by the compiler.
*/
int NextPrime( int );
void Producer( struct Prod * prodstruct )
{
int next; /* Will hold the prime we just produced. */
int prodid; /* Tells whether we are producer 1, 2 or 3. */
next = prodstruct -> startvalue; /* Get starting value from parameter. */
prodid = prodstruct -> id;/* Get producer number from parameter. */
while( 1 ) /* Loop forever. */
{
next = NextPrime (next);/* Produce a new prime. */
printf("\nNext Prime from producer %d is %d",prodid,next); /* Informational output. */
PutFifo(next); /* Write prime into FIFO. */
// oslab_yield(); /* Perhaps we should yield here? */
}
}
void Consumer( int * tal )
{
int next; /* Will hold the prime we are to consume. */
int consid = *tal; /* Tells whether we are consumer 1 or 2. */
while( 1 ) /* Loop forever. */
{
next = GetFifo(); /* Get a newly produced prime from the FIFO. */
printf("\nConsumer %d gets Prime %d ",consid, next); /* Informational output. */
Sleep(2000); /* Symbolic work. */
//oslab_yield(); /* Perhaps we should yield here? */
}
}
int main( void )
{
int new_thread_id; /* Thread ID variable. */
struct Prod prod1, prod2, prod3; /* Producer starting-values. */
int cons1, cons2; /* Consumer starting-values. */
rdaddr = 0; /* FIFO initialization. */
wraddr = 0; /* FIFO initialization. */
printf("\nSystem starting...");
prod1.startvalue = 2000;
prod1.id = 1;
prod2.startvalue = 5000;
prod2.id = 2;
prod3.startvalue = 8000;
prod3.id = 3;
cons1 = 1;
cons2 = 2;
new_thread_id = oslab_create_thread((void *)Producer, &prod1, &(stack1[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 1" );
printf("\nProducer %d is created with thread-ID %d", prod1.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Producer, &prod2, &(stack2[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 2" );
printf("\nProducer %d is created with thread-ID %d", prod2.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Producer, &prod3, &(stack3[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 3" );
printf("\nProducer %d is created with thread-ID %d", prod3.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Consumer, &cons1, &(stack4[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Consumer 1" );
printf("\nConsumer %d is created with thread-ID %d", cons1, new_thread_id);
new_thread_id = oslab_create_thread((void *)Consumer, &cons2, &(stack5[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Consumer 2" );
printf("\nConsumer %d is created with thread-ID %d", cons2, new_thread_id);
oslab_idle(); /* Must be called here! */
}
/*
* NextPrime
*
* Return the first prime number larger than the integer
* given as a parameter. The integer must be positive.
*/
#define PRIME_FALSE 0 /* Constant to help readability. */
#define PRIME_TRUE 1 /* Constant to help readability. */
int NextPrime( int inval )
{
int perhapsprime; /* Holds a tentative prime while we check it. */
int testfactor; /* Holds various factors for which we test perhapsprime. */
int found; /* Flag, false until we find a prime. */
if (inval < 3 ) /* Initial sanity check of parameter. */
{
if(inval <= 0) return(1); /* Return 1 for zero or negative input. */
if(inval == 1) return(2); /* Easy special case. */
if(inval == 2) return(3); /* Easy special case. */
}
else
{
/* Testing an even number for primeness is pointless, since
* all even numbers are divisible by 2. Therefore, we make sure
* that perhapsprime is larger than the parameter, and odd. */
perhapsprime = ( inval + 1 ) | 1 ;
}
/* While prime not found, loop. */
for( found = PRIME_FALSE; found != PRIME_TRUE; perhapsprime += 2 )
{
/* Check factors from 3 up to perhapsprime/2. */
for( testfactor = 3; testfactor <= (perhapsprime >> 1) + 1; testfactor += 1 )
{
found = PRIME_TRUE; /* Assume we will find a prime. */
if( (perhapsprime % testfactor) == 0 ) /* If testfactor divides perhapsprime... */
{
found = PRIME_FALSE; /* ...then, perhapsprime was non-prime. */
goto check_next_prime; /* Break the inner loop, go test a new perhapsprime. */
}
}
check_next_prime:; /* This label is used to break the inner loop. */
if( found == PRIME_TRUE ) /* If the loop ended normally, we found a prime. */
{
return( perhapsprime ); /* Return the prime we found. */
}
}
return( perhapsprime ); /* When the loop ends, perhapsprime is a real prime. */
}
When I run the program, the beginning of the FIFO queue is written over and it seems that the first 30 primes are lost when the consumer starts:
Consumer 1 gets Prime 5059
Consumer 1 gets Prime 5077
Consumer 1 gets Prime 5081
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 8017
Consumer 1 gets Prime 8039
Consumer 1 gets Prime 8053
Consumer 1 gets Prime 8059
Consumer 1 gets Prime 5051
Consumer 1 gets Prime 5059
Consumer 1 gets Prime 5077
Consumer 1 gets Prime 5081
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 8011
If I use the semaphores I don't get this problem and the consumer gets all the primes. Do you have an idea why I get this problem for this version of my project?
Update
Now I changed the Producer
function to call yield
and then the Producer will yield for each prime number that is produced (so therefore I think that only one prime will be produced for each Producer's timeslice).
#include <stdio.h>
#include "oslab_lowlevel_h.h"
int NextPrime( int );
#define FIFO_SIZE 10
/* Declare a structure to hold a producer's starting value,
* and an integer for the Producer-number (Producer 1, 2 or 3). */
struct Prod {
int startvalue;
int id;
};
unsigned int stack1[0x400]; /* Stack for thread 1 */
unsigned int stack2[0x400]; /* Stack for thread 2 */
unsigned int stack3[0x400]; /* Stack for thread 3 */
unsigned int stack4[0x400]; /* Stack for thread 4 */
unsigned int stack5[0x400]; /* Stack for thread 5 */
/* Declare variables for the First-In-First-Out Queue */
int Fifo[FIFO_SIZE]; /* Array holding FIFO queue data. */
int rdaddr; /* Next unread entry when reading from queue. */
int wraddr; /* Next free entry when writing into queue. */
/* Declaration of semaphore variables.
*
* Sorry for the lack of comments, but part of the purpose of the lab
* is that you should find things out by reading the actual code. */
int rdmutex = 1;
int wrmutex = 1;
int nrempty = FIFO_SIZE;
int nrfull = 0;
/*
* fatal_error
*
* Print a message, then stop execution.
* This function never returns; after printing
* the message, it enters an infinite loop.
*/
void fatal_error( char * msg)
{
printf( "\nFatal error: %s\n", msg );
while( 1 );
}
/*
* Sleep
*
* Delay execution by keeping the CPU busy for a while,
* counting down to zero.
*/
void Sleep (int n)
{
while (n--);
}
void Signal( int *sem )
{
oslab_begin_critical_region();
*sem = *sem + 1;
oslab_end_critical_region();
}
void Wait( int *sem )
{
/* Disable interrupts. */
oslab_begin_critical_region();
while ( *sem <= 0 )
{
/* If we should wait, enable interrupts again. */
oslab_end_critical_region();
// oslab_yield(); /* Perhaps we should yield here? */
/* Disable interrupts again before next iteration in loop. */
oslab_begin_critical_region();
}
/* We have waited long enough - the semaphore-value is now
* greater than zero. Decrease it. */
*sem = *sem - 1;
/* Enable interrupts again. */
oslab_end_critical_region();
}
/*
* PutFifo
*
* Insert an integer into the FIFO queue.
*/
void PutFifo( int tal )
{
// Wait (&nrempty); /* Wait for nrempty? */
// Wait (&wrmutex); /* Wait for wrmutex? */
Fifo[wraddr] = tal; /* Write to FIFO array. */
// printf("\nPutFifo: %d ", tal); /* Optional debug output */
// printf("\nwraddr = %d ", wraddr); /* Optional debug output. */
wraddr = wraddr + 1; /* Increase index into FIFO array,
to point to the next free position. */
/* Wrap around the index, if it has reached the end of the array. */
if (wraddr == FIFO_SIZE ) wraddr = 0;
// Signal (&wrmutex); /* Signal wrmutex? */
// Signal (&nrfull); /* Signal nrfull? */
}
/*
* GetFifo
*
* Extract the next integer from the FIFO queue.
*/
int GetFifo( void )
{
int retval; /* Declare temporary for return value. */
// Wait (&nrfull); /* Wait for nrfull? */
// Wait (&rdmutex); /* Wait for rdmutex? */
retval = Fifo[rdaddr]; /* Get value from FIFO array. */
// printf("\nGetFifo: %d ", retval); /* Optional debug output */
// printf("\nrdaddr = %d ", rdaddr); /* Optional debug output */
rdaddr = rdaddr + 1; /* Increase index into FIFO array,
to point to the next free position. */
/* Wrap around the index, if it has reached the end of the array. */
if (rdaddr == FIFO_SIZE ) rdaddr = 0;
// Signal (&rdmutex); /* Signal rdmutex? */
// Signal (&nrempty); /* Signal nrempty? */
return (retval); /* Return value fetched from FIFO. */
}
int NextPrime( int );
void Producer( struct Prod * prodstruct )
{
int next; /* Will hold the prime we just produced. */
int prodid; /* Tells whether we are producer 1, 2 or 3. */
next = prodstruct -> startvalue; /* Get starting value from parameter. */
prodid = prodstruct -> id;/* Get producer number from parameter. */
while( 1 ) /* Loop forever. */
{
next = NextPrime (next);/* Produce a new prime. */
printf("\nNext Prime from producer %d is %d",prodid,next); /* Informational output. */
PutFifo(next); /* Write prime into FIFO. */
oslab_yield(); /* Perhaps we should yield here? */
}
}
void Consumer( int * tal )
{
int next; /* Will hold the prime we are to consume. */
int consid = *tal; /* Tells whether we are consumer 1 or 2. */
while( 1 ) /* Loop forever. */
{
next = GetFifo(); /* Get a newly produced prime from the FIFO. */
printf("\nConsumer %d gets Prime %d ",consid, next); /* Informational output. */
Sleep(2000); /* Symbolic work. */
// oslab_yield(); /* Perhaps we should yield here? */
}
}
int main( void )
{
int new_thread_id; /* Thread ID variable. */
struct Prod prod1, prod2, prod3; /* Producer starting-values. */
int cons1, cons2; /* Consumer starting-values. */
rdaddr = 0; /* FIFO initialization. */
wraddr = 0; /* FIFO initialization. */
printf("\nSystem starting...");
prod1.startvalue = 2000;
prod1.id = 1;
prod2.startvalue = 5000;
prod2.id = 2;
prod3.startvalue = 8000;
prod3.id = 3;
cons1 = 1;
cons2 = 2;
new_thread_id = oslab_create_thread((void *)Producer, &prod1, &(stack1[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 1" );
printf("\nProducer %d is created with thread-ID %d", prod1.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Producer, &prod2, &(stack2[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 2" );
printf("\nProducer %d is created with thread-ID %d", prod2.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Producer, &prod3, &(stack3[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Producer 3" );
printf("\nProducer %d is created with thread-ID %d", prod3.id, new_thread_id);
new_thread_id = oslab_create_thread((void *)Consumer, &cons1, &(stack4[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Consumer 1" );
printf("\nConsumer %d is created with thread-ID %d", cons1, new_thread_id);
new_thread_id = oslab_create_thread((void *)Consumer, &cons2, &(stack5[0x3ff]));
if( new_thread_id < 0 ) fatal_error( "cannot start Consumer 2" );
printf("\nConsumer %d is created with thread-ID %d", cons2, new_thread_id);
oslab_idle(); /* Must be called here! */
}
The change is that I commented in the code oslab_yield(); /* Perhaps we should yield here? */
so now I suppose that there is only one prime number produced per timeslice(?)
System starting...
Producer 1 is created with thread-ID 1
Producer 2 is created with thread-ID 2
Producer 3 is created with thread-ID 3
Consumer 1 is created with thread-ID 4
Consumer 2 is created with thread-ID 5
#### Thread yielded after using 1 tick.
Performing thread-switch number 1. The system has been running for 1 ticks.
Switching from thread-ID 0 to thread-ID 1.
Next Prime from producer 1 is 2003
#### Thread yielded after using 5 ticks.
Performing thread-switch number 2. The system has been running for 6 ticks.
Switching from thread-ID 1 to thread-ID 2.
Next Prime from producer 2 is 5003
#### Thread yielded after using 11 ticks.
Performing thread-switch number 3. The system has been running for 17 ticks.
Switching from thread-ID 2 to thread-ID 3.
Next Prime from producer 3 is 8009
#### Thread yielded after using 16 ticks.
Performing thread-switch number 4. The system has been running for 33 ticks.
Switching from thread-ID 3 to thread-ID 4.
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Performing thread-switch number 5. The system has been running for 133 ticks.
Switching from thread-ID 4 to thread-ID 5.
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Performing thread-switch number 6. The system has been running for 233 ticks.
Switching from thread-ID 5 to thread-ID 0.
#### Thread yielded after using 0 ticks.
Performing thread-switch number 7. The system has been running for 233 ticks.
Switching from thread-ID 0 to thread-ID 1.
Next Prime from producer 1 is 2011
#### Thread yielded after using 5 ticks.
Performing thread-switch number 8. The system has been running for 238 ticks.
Switching from thread-ID 1 to thread-ID 2.
Next Prime from producer 2 is 5009
#### Thread yielded after using 11 ticks.
Performing thread-switch number 9. The system has been running for 249 ticks.
Switching from thread-ID 2 to thread-ID 3.
Next Prime from producer 3 is 8011
#### Thread yielded after using 16 ticks.
Performing thread-switch number 10. The system has been running for 265 ticks.
Switching from thread-ID 3 to thread-ID 4.
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime
Performing thread-switch number 11. The system has been running for 365 ticks.
Switching from thread-ID 4 to thread-ID 5.
Consumer 2 gets Prime 5009
Consumer 2 gets Prime 8011
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 2011
Consumer 2 gets Prime 5009
Consumer 2 gets Prime 8011
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 2011
Consumer 2 gets Prime 5009
Consumer 2 gets Prime 8011
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Consumer 2 gets Prime 8009
Consumer 2 gets Prime 2011
Consumer 2 gets Prime 5009
Consumer 2 gets Prime 8011
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 0
Consumer 2 gets Prime 2003
Consumer 2 gets Prime 5003
Performing thread-switch number 12. The system has been running for 465 ticks.
Switching from thread-ID 5 to thread-ID 0.
#### Thread yielded after using 0 ticks.
Performing thread-switch number 13. The system has been running for 465 ticks.
Switching from thread-ID 0 to thread-ID 1.
Next Prime from producer 1 is 2017
#### Thread yielded after using 5 ticks.
Performing thread-switch number 14. The system has been running for 470 ticks.
Switching from thread-ID 1 to thread-ID 2.
Next Prime from producer 2 is 5011
#### Thread yielded after using 11 ticks.
Performing thread-switch number 15. The system has been running for 481 ticks.
Switching from thread-ID 2 to thread-ID 3.
Next Prime from producer 3 is 8017
#### Thread yielded after using 16 ticks.
Performing thread-switch number 16. The system has been running for 497 ticks.
Switching from thread-ID 3 to thread-ID 4.
2094
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 2017
Consumer 1 gets Prime 5011
Consumer 1 gets Prime 8017
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 2017
Consumer 1 gets Prime 5011
Consumer 1 gets Prime 8017
Consumer 1 gets Prime 0
Consumer 1 gets Prime 2003
Consumer 1 gets Prime 5003
Consumer 1 gets Prime 8009
Consumer 1 gets Prime 2011
Consumer 1 gets Prime 5009
Consumer 1 gets Prime 8011
Consumer 1 gets Prime 2017
Consumer 1 gets Prime 5011
Consumer 1 gets Prime 8017
Nick, you have a couple of issues.
First, the producers can't just write into the fifo. You need to check that it has room. (This is that wraddr+1 != rdaddr. Modulo FIFO_SIZE) You also need the consumers to check that the fifo isn't empty. (This is wraddr != rdaddr. Modulo FIFO_SIZE)
The next problem deals with scheduling. How is the oslab scheduler implemented? Is there only one thread of execution? If so, it is pre-emptive, etc? In any event, if one thread gets part way through the PutFifo and the next thread starts PutFifo, there is no protection against dual updating. In fact, wraddr could be corrupted so that you lose entries. You can do a generalized Dekker algorithm (see wikipedia - at the bottom of the page you will see pointers to Petersen and other algorithms). Consumer side has similar problem.
I think that your problems are a combination of the two issues above. So how do you fix it? I would write a Sync and Unsync routine for each addr (wr and rd). Under the cover, you could do mutexes, etc for the second thing you want to do. You could also do a Dekker, etc for the first pass you want to do. Put the Sync before the PutFifo and Unsync after PutFifo. Similarly for GetFifo.
Let me know if you need anything else.