私はFIFOキュー、プロデューサーとコンシューマーを持っており、この配置だけを除いて機能するさまざまな組み合わせで試しています。これは、3つのプロデューサー、2つのコンシューマー、FIFO用の10のスロット、および最初はセマフォなしで実行でき、次にセマフォをアクティブにして実行できるはずです。
#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. */
}
プログラムを実行すると、FIFOキューの先頭が上書きされ、コンシューマーが起動すると最初の30個の素数が失われるようです。
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
セマフォを使用する場合、この問題は発生せず、消費者はすべての素数を取得します。このバージョンのプロジェクトでこの問題が発生する理由がわかりますか?
アップデート
ここで、Producer
呼び出す関数を変更するyield
と、プロデューサーは生成される素数ごとに生成されます(したがって、各プロデューサーのタイムスライスに対して1つの素数のみが生成されると思います)。
#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! */
}
変更点は、コードでコメントしたoslab_yield(); /* Perhaps we should yield here? */
ため、タイムスライスごとに生成される素数は1つだけだと思います(?)
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