Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何处理生产者-消费者模式的FIFO队列_C_Semaphore_Producer Consumer_Fifo - Fatal编程技术网

C 如何处理生产者-消费者模式的FIFO队列

C 如何处理生产者-消费者模式的FIFO队列,c,semaphore,producer-consumer,fifo,C,Semaphore,Producer Consumer,Fifo,我有一个FIFO队列,生产者和消费者,我尝试不同的组合,除了这种安排。我应该能够在3个生产者,2个消费者,10个FIFO插槽的情况下运行它,并且一开始没有信号量,然后在信号量激活的情况下运行它 #include <stdio.h> #include "oslab_lowlevel_h.h" int NextPrime( int ); #define FIFO_SIZE 10 /* Declare a structure to hold a producer's starting

我有一个FIFO队列,生产者和消费者,我尝试不同的组合,除了这种安排。我应该能够在3个生产者,2个消费者,10个FIFO插槽的情况下运行它,并且一开始没有信号量,然后在信号量激活的情况下运行它

#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. */
}
如果我使用信号量,我就不会遇到这个问题,而消费者得到所有的素数。你知道我为什么会在这个版本的项目中遇到这个问题吗

更新 现在我将
Producer
函数更改为调用
yield
,然后Producer将为生成的每个素数生成一个素数(因此我认为每个Producer的时间片只生成一个素数)

  • 您的FIFO和信号量变量应该声明为volatile

  • 代码中没有任何内容调用
    Wait

  • 您的FIFO和信号量变量应该声明为volatile

  • 代码中没有任何内容调用
    Wait


  • 尼克,你有几个问题

    首先,制作人不能只是写入fifo。你需要检查一下它是否有空间。(这是wraddr+1!=rdaddr.Modulo FIFO_SIZE)您还需要使用者检查FIFO是否为空。(这是wraddr!=rdaddr.模FIFO_大小)

    下一个问题涉及调度。oslab调度程序是如何实现的?只有一个执行线程吗?如果是,它是先发制人的,等等?在任何情况下,如果一个线程部分通过PutFifo,而下一个线程启动PutFifo,则无法防止双重更新。事实上,wraddr可能会损坏,从而丢失条目。你可以做一个广义的Dekker算法(参见维基百科——在页面底部,你会看到指向Petersen和其他算法的指针)。消费者方面也有类似的问题

    我认为你的问题是上述两个问题的结合。那么你如何修复它呢?我会为每个addr(wr和rd)编写一个Sync和Unsync例程。在封面下,你可以为你想做的第二件事做互斥等。你也可以在你想做的第一次传球中做德克尔等动作。将同步放在PUTFIO之前,将不同步放在PUTFIO之后。GetFifo也是如此


    如果你还需要什么,请告诉我。

    尼克,你有几个问题

    首先,制作人不能只是写入fifo。你需要检查一下它是否有空间。(这是wraddr+1!=rdaddr.Modulo FIFO_SIZE)您还需要使用者检查FIFO是否为空。(这是wraddr!=rdaddr.模FIFO_大小)

    下一个问题涉及调度。oslab调度程序是如何实现的?只有一个执行线程吗?如果是,它是先发制人的,等等?在任何情况下,如果一个线程部分通过PutFifo,而下一个线程启动PutFifo,则无法防止双重更新。事实上,wraddr可能会损坏,从而丢失条目。你可以做一个广义的Dekker算法(参见维基百科——在页面底部,你会看到指向Petersen和其他算法的指针)。消费者方面也有类似的问题

    我认为你的问题是上述两个问题的结合。那么你如何修复它呢?我会为每个addr(wr和rd)编写一个Sync和Unsync例程。在封面下,你可以为你想做的第二件事做互斥等。你也可以在你想做的第一次传球中做德克尔等动作。将同步放在PUTFIO之前,将不同步放在PUTFIO之后。GetFifo也是如此


    如果您还需要什么,请告诉我。

    3。在没有同步机制(信号量或互斥)的情况下读取/写入全局变量。是的,如果我激活信号量,它就会工作。但它也应该在没有信号量的情况下工作,而且除了前30个左右的素数之外,它还工作。我会尝试用更多的细节来更新Q,它与信号量完美配合,但我也应该得到没有符号的素数。在没有同步机制(信号量或互斥)的情况下读取/写入全局变量。是的,如果我激活信号量,它就会工作。但它也应该在没有信号量的情况下工作,而且除了前30个左右的素数之外,它还工作。我会尝试用更多的细节来更新Q,它与信号量完美配合,但我也应该得到没有符号的素数。但第一个素数不是消费者,这仍然是完全不合逻辑的。对于这个错误,我们没有找到解释和解决方案。这是我在学习C语言时做的一个练习,我们不应该期望这些问题会破坏整个关于不合逻辑错误的研究。Prod1将23个素数转储到FIFO。第一个10被第二个10覆盖。prod1中的next3和prod2中的前7会覆盖这些数据。5059现在位于FIFO的第一个插槽中,消费者读取它。我上面的回答是,你需要检查你没有覆盖FIFO。需要比较Waddr和rdaddr。要正确执行此操作,您需要一个信号量来防止双重更新发生。仔细阅读我写的内容,让我知道你还需要什么。不要生气,这不是C问题,只是多线程问题。谢谢你的帮助。现在我认为,如果我只为Producer函数启用
    yield
    ,它就会工作。然后生产者将只产生一个素数,然后产生,消费者将从一开始就消费一切。很高兴听到,但是GetFifo是否受到双重更新的保护?如果一个线程必须在另一个线程执行之前显式地释放CPU,那么就可以了。如果没有(或者有多个内核),则使用者端需要保护rdaddr变量,防止两个使用者线程读取相同的素数。例如,第一个cons执行retval=Fifo[rdaddr],被中断,第二个cons执行相同的语句。两者都有相同的值,并且都可以执行下一个语句
    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 
    
    #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! */
    }
    
    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