c - Why does my producer - consumer pattern have unexpected output? -


in this excercise (producer - consumer), 3 producers 1 thread each , produce prime numbers. when run program, first prime number consumed not first produces, don't expected output. can please me find , correct bug?

here's main file pattern:

#include <stdio.h> #include "oslab_lowlevel_h.h"  int nextprime( int );  #define fifo_size 10  /* declare structure hold producer's starting value,  * , integer producer-number (producer 1, 2 or 3). */ struct prod {     int startvalue;     int id; };  unsigned int stack1[0x400]; /* stack thread 1 */ unsigned int stack2[0x400]; /* stack thread 2 */ unsigned int stack3[0x400]; /* stack thread 3 */ unsigned int stack4[0x400]; /* stack thread 4 */ unsigned int stack5[0x400]; /* stack thread 5 */  /* declare variables first-in-first-out queue */ int  fifo[fifo_size];        /* array holding fifo queue data. */ int  rdaddr;                /* next unread entry when reading queue. */ int  wraddr;                /* next free entry when writing queue. */  /* declaration of semaphore variables.  *   * sorry lack of comments, part of purpose of lab  * should find things out reading actual code. */ int  rdmutex = 1; int  wrmutex = 1; int  nrempty = fifo_size; int  nrfull = 0;  /*  * fatal_error  *   * print message, stop execution.  * function never returns; after printing  * message, enters infinite loop.  */ void fatal_error( char * msg) {   printf( "\nfatal error: %s\n", msg );   while( 1 ); }  /*  * sleep  *   * delay execution keeping cpu busy while,  * counting down zero.  */ void sleep (int n) {     while (n--); }  /*  * signal  *   * semaphore operation: add semaphore,  * possibly allowing other threads continue.  */ void signal( int *sem ) {   /* must disable interrupts, since operation    * *sem = *sem + 1    * require several machine instructions on nios2.    * if have timer-interrupt , thread-switch    * somewhere in middle of machine instructions,    * semaphore updated twice, or not @ all, or    * in other erroneous way.    */   oslab_begin_critical_region();   *sem = *sem + 1;   oslab_end_critical_region(); }  /*  * wait  *   * sempahore operation: check semaphore, ,  * wait if semaphore value 0 or less.  */ void wait( int *sem ) {   /* disable interrupts. */   oslab_begin_critical_region();   while ( *sem <= 0 )     {       /* if should wait, enable interrupts again. */       oslab_end_critical_region();        //  oslab_yield(); /* perhaps should yield here? */        /* disable interrupts again before next iteration in loop. */       oslab_begin_critical_region();     }     /* have waited long enough - semaphore-value      * greater zero. decrease it. */     *sem = *sem - 1;     /* enable interrupts again. */     oslab_end_critical_region(); }  /*  * putfifo  *   * insert integer fifo queue.  */ void putfifo( int tal ) {   //  wait (&nrempty);      /* wait nrempty? */   //  wait (&wrmutex);      /* wait wrmutex? */    fifo[wraddr] = tal;       /* write fifo array. */     //  printf("\nputfifo:  %d ", tal); /* optional debug output */     //  printf("\nwraddr = %d ", wraddr); /* optional debug output. */   wraddr = wraddr + 1;      /* increase index fifo array,                                point next free position. */   /* wrap around index, if has reached end of array. */   if (wraddr == fifo_size ) wraddr = 0;    //  signal (&wrmutex);    /* signal wrmutex? */   //  signal (&nrfull);     /* signal nrfull? */ }  /*  * getfifo  *   * extract next integer fifo queue.  */ int getfifo( void ) {   int retval;               /* declare temporary return value. */    //  wait (&nrfull);       /* wait nrfull? */   //  wait (&rdmutex);      /* wait rdmutex? */    retval = fifo[rdaddr];    /* value fifo array. */     //  printf("\ngetfifo:  %d ", retval); /* optional debug output */     //  printf("\nrdaddr = %d ", rdaddr); /* optional debug output */   rdaddr = rdaddr + 1;      /* increase index fifo array,                                point next free position. */   /* wrap around index, if has reached end of array. */   if (rdaddr == fifo_size ) rdaddr = 0;    //  signal (&rdmutex);    /* signal rdmutex? */   //  signal (&nrempty);    /* signal nrempty? */    return (retval);          /* return value fetched fifo. */ }  /*  * nextprime  *   * return first prime number larger integer  * given parameter. integer must positive.  *   * *** nextprime outside focus of assignment. ***  * definition of nextprime can found @ end of file.  * short declaration here required compiler.  */ int nextprime( int );  void producer( struct prod * prodstruct ) {   int next;                 /* hold prime produced. */   int prodid;               /* tells whether producer 1, 2 or 3. */   next = prodstruct -> startvalue; /* starting value parameter. */   prodid = prodstruct -> id;/* producer number parameter. */   while( 1 )                /* loop forever. */   {     next = nextprime (next);/* produce new prime. */     printf("\nnext prime producer %d %d",prodid,next); /* informational output. */     putfifo(next);          /* write prime fifo. */   //  oslab_yield();        /* perhaps should yield here? */    } }  void consumer( int * tal ) {   int next;                 /* hold prime consume. */   int consid = *tal;        /* tells whether consumer 1 or 2. */   while( 1 )                /* loop forever. */   {     next = getfifo();       /* newly produced prime fifo. */     printf("\nconsumer %d gets prime %d ",consid, next); /* informational output. */     sleep(2000);            /* symbolic work. */   //  oslab_yield();        /* perhaps 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 created 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 created 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 created 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 created 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 created thread-id %d", cons2, new_thread_id);    oslab_idle(); /* must called here! */ }   /*  * nextprime  *   * return first prime number larger integer  * given parameter. integer must positive.  */ #define prime_false   0     /* constant readability. */ #define prime_true    1     /* constant readability. */ int nextprime( int inval ) {    int perhapsprime;        /* holds tentative prime while check it. */    int testfactor;          /* holds various factors test perhapsprime. */    int found;               /* flag, false until find prime. */     if (inval < 3 )          /* initial sanity check of parameter. */    {      if(inval <= 0) return(1);  /* return 1 0 or negative input. */      if(inval == 1) return(2);  /* easy special case. */      if(inval == 2) return(3);  /* easy special case. */    }    else    {      /* testing number primeness pointless, since       * numbers divisible 2. therefore, make sure       * perhapsprime larger parameter, , odd. */      perhapsprime = ( inval + 1 ) | 1 ;    }    /* while prime not found, loop. */    for( found = prime_false; found != prime_true; perhapsprime += 2 )    {      /* check factors 3 perhapsprime/2. */      for( testfactor = 3; testfactor <= (perhapsprime >> 1) + 1; testfactor += 1 )      {        found = prime_true;      /* assume find prime. */        if( (perhapsprime % testfactor) == 0 ) /* if testfactor divides perhapsprime... */        {          found = prime_false;   /* ...then, perhapsprime non-prime. */          goto check_next_prime; /* break inner loop, go test new perhapsprime. */        }      }      check_next_prime:;         /* label used break inner loop. */      if( found == prime_true )  /* if loop ended normally, found prime. */      {        return( perhapsprime );  /* return prime found. */      }     }    return( perhapsprime );      /* when loop ends, perhapsprime real prime. */ }  

the rest of files available here.

when run code expected output producers don't expected output consumers:

system starting... producer 1 created thread-id 1 producer 2 created thread-id 2 producer 3 created thread-id 3 consumer 1 created thread-id 4 consumer 2 created thread-id 5 #### thread yielded after using 1 tick. performing thread-switch number 1. system has been running 1 ticks. switching thread-id 0 thread-id 1.  next prime producer 1 2003 putfifo:  2003  wraddr = 0  next prime producer 1 2011 putfifo:  2011  wraddr = 1  next prime producer 1 2017 putfifo:  2017  wraddr = 2  next prime producer 1 2027 putfifo:  2027  wraddr = 3  next prime producer 1 2029 putfifo:  2029  wraddr = 4  next prime producer 1 2039 putfifo:  2039  wraddr = 5  next prime producer 1 2053 putfifo:  2053  wraddr = 6  next prime producer 1 2063 putfifo:  2063  wraddr = 7  next prime producer 1 2069 putfifo:  2069  wraddr = 8  next prime producer 1 2081 putfifo:  2081  wraddr = 9  next prime producer 1 2083 putfifo:  2083  wraddr = 0  next prime producer 1 2087 putfifo:  2087  wraddr = 1  next prime producer 1 2089 putfifo:  2089  wraddr = 2  next prime producer 1 2099 putfifo:  2099  wraddr = 3  next prime producer 1 2111 putfifo:  2111  wraddr = 4  next prime producer 1 2113 putfifo:  2113  wraddr = 5  next prime producer 1 2129 putfifo:  2129  wraddr = 6  next prime producer 1 2131 putfifo:  2131  wraddr = 7  next prime producer 1 2137 putfifo:  2137  wraddr = 8  next prime producer 1 2141 putfifo:  2141  wraddr = 9  next prime producer 1 2143 putfifo:  2143  wraddr = 0  next prime producer 1 2153 putfifo:  2153  wraddr = 1  performing thread-switch number 2. system has been running 101 ticks. switching thread-id 1 thread-id 2.  next prime producer 2 5003 putfifo:  5003  wraddr = 2  next prime producer 2 5009 putfifo:  5009  wraddr = 3  next prime producer 2 5011 putfifo:  5011  wraddr = 4  next prime producer 2 5021 putfifo:  5021  wraddr = 5  next prime producer 2 5023 putfifo:  5023  wraddr = 6  next prime producer 2 5039 putfifo:  5039  wraddr = 7  next prime producer 2 5051 putfifo:  5051  wraddr = 8  next prime producer 2 5059 putfifo:  5059  wraddr = 9  next prime producer 2 5077 putfifo:  5077  wraddr = 0  next prime producer 2 5081 putfifo:  5081  wraddr = 1  performing thread-switch number 3. system has been running 201 ticks. switching thread-id 2 thread-id 3.  next prime producer 3 8009 putfifo:  8009  wraddr = 2  next prime producer 3 8011 putfifo:  8011  wraddr = 3  next prime producer 3 8017 putfifo:  8017  wraddr = 4  next prime producer 3 8039 putfifo:  8039  wraddr = 5  next prime producer 3 8053 putfifo:  8053  wraddr = 6  next prime producer 3 8059 putfifo:  8059  wraddr = 7  performing thread-switch number 4. system has been running 301 ticks. switching thread-id 3 thread-id 4.  getfifo:  5077  rdaddr = 0  consumer 1 gets prime 5077  getfifo:  5081  rdaddr = 1  consumer 1 gets prime 5081  getfifo:  8009  rdaddr = 2  consumer 1 gets prime 8009  getfifo:  8011  rdaddr = 3  consumer 1 gets prime 8011  getfifo:  8017  rdaddr = 4  consumer 1 gets prime 8017  getfifo:  8039  rdaddr = 5  consumer 1 gets prime 8039  getfifo:  8053  rdaddr = 6  consumer 1 gets prime 8053  getfifo:  8059  rdaddr = 7  consumer 1 gets prime 8059  getfifo:  5051  rdaddr = 8  consumer 1 gets prime 5051  getfifo:  5059  rdaddr = 9  consumer 1 gets prime 5059  getfifo:  5077  rdaddr = 0  consumer 1 gets prime 5077  getfifo:  5081  

could please tell me why first 30 primes overwritten when following specification , removing comments code activate instructor has prepared study? i've been unable complete exercise months since i'm not getting help. first 30 primes myseriously overwritten , program should not changed (it homework). asked instructor , didn't, said i'm using newer versions of software. try older versions of softare doesn't seem solution.

update

the strategy can think of start using debugger , inspect fifo adt during execution. don't have experience using gdb please me if can.

this code can't possibly expected work correctly if don't uncomment wait , signal calls inside putfifo , getfifo functions. if appear work under circumstances on computer, pure luck.

first off, if 1 or more of producer threads fill fifo buffer before switching 1 of consumer threads, of data going lost.

you can see in example output. producer threads have generated 38 values before first consumer thread gets chance run. , because buffer size 10, first value consumer going read 31st value produced (i.e. last value written wraddr 0).

╔═══════╦════════╦═══════╗ ║ count ║ wraddr ║ value ║ ╠═══════╬════════╬═══════╣ ║    .. ║     .. ║    .. ║ ║    29 ║      8 ║  5051 ║ ║    30 ║      9 ║  5059 ║ ║    31 ║      0 ║  5077 ║ <- consumer starts here ║    32 ║      1 ║  5081 ║ ║    33 ║      2 ║  8009 ║ ║    34 ║      3 ║  8011 ║ ║    35 ║      4 ║  8017 ║ ║    36 ║      5 ║  8039 ║ ║    37 ║      6 ║  8053 ║ ║    38 ║      7 ║  8059 ║ ╚═══════╩════════╩═══════╝ 

morever, if consumer threads read more data available in fifo buffer before switching 1 of producer threads, going end reading same values more once. again can see example output. consumer thread reads items 31 38, wraps around items 29 , 30 (the last values @ wraddr 8 , 9), before repeating item 31 again.

this isn't worst thing happen though. in true preemptive multithreading system, producer thread preempted halfway through putfifo function. imagine 1 of producer threads writing fifo buffer when wraddr 9. let's executes these 2 lines.

fifo[wraddr] = tal;       /* write fifo array. */ wraddr = wraddr + 1;      /* increase index fifo array, 

at point wraddr 10, before function has chance check overflow (and wrap index 0), thread gets preempted 1 of producer threads. , since wraddr 10, new producer going writing past end of buffer, potentially causing app crash.

if survives, wraddr incremented again (becoming 11), still won't wrap zero, because overflow check expecting exact match fifo_size. if doesn't crash immediately, it's sure crash @ point, because wraddr continue getting bigger , bigger, overwriting more , more memory.

the bottom line if want code work going have add synchronisation calls.


Comments

Popular posts from this blog

Perl - how to grep a block of text from a file -

delphi - How to remove all the grips on a coolbar if I have several coolbands? -

javascript - Animating array of divs; only the final element is modified -