1  /*---------------------------------------------------------------
   2  *
   3  * B2  ROCK, PAPER, SCISSORS
   4  *
   5  *--------------------------------------------------------------*/
   6  
   7  #define  SYSTEMID_WINXP_VC2008
   8  //#define  SYSTEMID_LINUX
   9  #define  FETCH 2
  10  /*---------------------------------------------------------------
  11  *
  12  *  #includes and #defines for                     SYSTEMID_WINXP_VC2008
  13  *
  14  *--------------------------------------------------------------*/
  15  #ifdef   SYSTEMID_WINXP_VC2008
  16  #define _CRT_SECURE_NO_DEPRECATE
  17  //#include "stdafx.h"
  18  #include <stddef.h>  // Needed for VC2008?
  19  #include <stdio.h>
  20  #include <windows.h>
  21  #include <conio.h>
  22  #include <process.h>
  23  #include <time.h>
  24  #include <sys/timeb.h>
  25  #define  threadArg_t int
  26  #define  threadGetParm vptr
  27  #define  TIME0
  28  #endif
  29  
  30  /*---------------------------------------------------------------
  31  *
  32  *  #includes and #defines for                     SYSTEMID_LINUX
  33  *
  34  *--------------------------------------------------------------*/
  35  #ifdef   SYSTEMID_LINUX
  36  #include <stdio.h>
  37  #include <stdlib.h>
  38  #include <string.h>
  39  #include <time.h>
  40  #include <stdarg.h>
  41  #include <sys/types.h>
  42  #include <sys/time.h>
  43  #include <pthread.h>
  44  #define  threadArg_t int*
  45  #define  threadGetParm  *(int*)vptr
  46  #define  TIME2
  47  #endif
  48  
  49  #define NUMBER_OF_THREADS     12
  50  // The maximum number of threads is currently 12.
  51  #define NUMBER_OF_ITERATIONS  10
  52  
  53  #define NONE      0  // Set by MAIN.   Step 1.
  54  #define ROCK      1  // Set by THRED.  Step 2.
  55  #define PAPER     2  // Set by THRED.  Step 2.
  56  #define SCISSORS  3  // Set by THRED.  Step 2.
  57  #define END       4  // Set by MAIN.   Step 3.
  58  #define ENDED     5  // Set by THRED.  Step 4.
  59  
  60  #define ID        0  // ID of thred:  0, 1, 2, . . . .
  61  #define PTR       1  // Pointer to ID; needed by _beginthread.
  62  #define RULE      2  // What discipline does thred follow?
  63  #define SUM       3  // Total of successes for thred.
  64  #define THROW     4  // Main sets to NONE or END; thred sets to ROCK, PAPER, or SCISSORS, or ENDED.
  65  #define RANDOM    5  // Main must set; if threads do rand(), they all see the same sequence of values.
  66  
  67  #define MAIN_SPIN_LIM   10000000
  68  #define THRD_SPIN_LIM   10000000
  69  
  70  // Disciplines followed by thred in choosing ROCK, PAPER, or SCISSORS.
  71  #define ALWAYS_ROCK     0
  72  #define ALWAYS_PAPER    1
  73  #define ALWAYS_SCISSORS 2
  74  #define ALWAYS_MOST     3
  75  #define ALWAYS_MIDDLE   4
  76  #define ALWAYS_LEAST    5
  77  #define ALWAYS_RANDOM   6
  78  
  79  #define  HESIT8   printf("\n\nPress ENTER to continue."); fgets(ans,ans_length,stdin);
  80  
  81  #define  TIME    0
  82  #define  DUR     1
  83  #define  SM_DUR  2
  84  
  85  void thred(void*);
  86  void dump(int);
  87  long record_time();
  88  void printtd(char*);
  89  void put_time(int form, long sc, int ms, char* z);
  90  
  91  long presc=0,difsc,nowsc=0;
  92  int  prems=0,difms,nowms=0;
  93  long rel_time;            /* Relative time to previous call to record_time().*/
  94  long time_test_start_sc;   // Starting time of the current test.
  95  int  time_test_start_ms;
  96  
  97  #ifdef TIME0
  98    int hour_delta = 0;
  99    struct timeb tmb;
 100  #endif
 101  
 102  #ifdef TIME2
 103    int hour_delta = 5; /* Local time - GMT, in hours. */
 104    struct timeval tp;
 105  #endif
 106  
 107  char duration1[13];
 108  int  duration2;
 109  char outchar[61];
 110  const int yearzero = 2002;       // These two values must change simultaneously.  hhh
 111  const int timezero = 1009843201; // = 00:00:00 am on Jan 1, 2002.
 112  char   time_stamp[13];
 113  
 114  /*---------------------------------------------------------------
 115  *
 116  *  Define parameter values                        
 117  *
 118  *--------------------------------------------------------------*/
 119  char ans[99];
 120  const int ans_length = 99-1;
 121  int   sort[3];
 122  int   debug = 0;
 123  FILE *fout;
 124  char* outfilename = "rpsout";
 125  
 126  int s[NUMBER_OF_THREADS][6];
 127  int totals[4];
 128  
 129  char names[7][20] = {"ALWAYS_ROCK    ","ALWAYS_PAPER   ","ALWAYS_SCISSORS","ALWAYS_MOST    ","ALWAYS_MIDDLE  ","ALWAYS_LEAST   ","ALWAYS_RANDOM  "};
 130  
 131  /*---------------------------------------------------------------
 132  *
 133  *  Define parameter values                        SYSTEMID_LINUX
 134  *
 135  *--------------------------------------------------------------*/
 136  #ifdef   SYSTEMID_LINUX
 137  /*
 138  int vptr;
 139  int n0=0,n1=1,n2=2,n3=3,n4=4,n5=5,n6=6,n7=7;
 140  int* vptr0 = &n0;
 141  int* vptr1 = &n1;
 142  int* vptr2 = &n2;
 143  int* vptr3 = &n3;
 144  int* vptr4 = &n4;
 145  int* vptr5 = &n5;
 146  int* vptr6 = &n6;
 147  int* vptr7 = &n7; */
 148  pthread_t thrdi;
 149  #endif
 150  
 151  /*---------------------------------------------------------------
 152  * MAIN                                               
 153  *
 154  *--------------------------------------------------------------*/
 155  int main()
 156  {
 157    int i = 0, iteration_count = 0, temp, spin_count;
 158  
 159    if ((fout = fopen(outfilename,"w")) == NULL)  
 160    {
 161      printf("\n  Line 161. MAIN(): Error on trying to open output file:  %s.",outfilename);
 162      return(134);
 163    }
 164    
 165    printtd("Begin execution of Rock, Paper, Scissors.");
 166    time_test_start_sc = nowsc;   // Starting time of the current test.
 167    time_test_start_ms = nowms;
 168  
 169    fprintf(fout,"\nFETCH = %d.",FETCH);
 170    // Initalize with nonzero values; else a hang can happen.
 171    sort[0]=1; sort[1]=2; sort[2]=3;
 172    // Initialize s[].  Start threads. 
 173    for (i = 0;i < NUMBER_OF_THREADS;i++)
 174    {
 175      s[i][ID]     = i;
 176      s[i][PTR]    = (long)(&s[i][ID]);
 177      s[i][THROW]  = NONE;                                                  // WRITE SHARED OPERAND.   
 178      s[i][RULE]   = ALWAYS_RANDOM;  
 179      s[i][RANDOM] = rand()%3+1;  // = 1, 2, or 3; = ROCK, PAPER, or SCISSORS.  // WRITE SHARED OPERAND.
 180  #ifdef SYSTEMID_WINXP_VC2008
 181      _beginthread( thred, 0, &s[i][ID]);
 182  #endif
 183  #ifdef SYSTEMID_LINUX
 184      pthread_create(&thrdi,NULL,(void*)thred,(void*)&s[i][ID]);
 185  #endif
 186    } 
 187  
 188    while(1)  
 189    {
 190      s[ 0][RULE] = ALWAYS_ROCK;          // Choose algorithms the threads will use
 191      if (NUMBER_OF_THREADS <  3) break;  // to select ROCK, PAPER, SCISSORS.
 192      s[ 2][RULE] = ALWAYS_PAPER;         // s[][RULE] is written only once (here).
 193      if (NUMBER_OF_THREADS <  5) break;  // It is read repeatedly by the threds.
 194      s[ 4][RULE] = ALWAYS_SCISSORS;      //
 195      if (NUMBER_OF_THREADS <  7) break;  // Why this pattern of disciplines?
 196      s[ 6][RULE] = ALWAYS_MOST;          // So I could debug with just a few threads
 197      if (NUMBER_OF_THREADS <  9) break;  // and still have a variety of disciplines,
 198      s[ 8][RULE] = ALWAYS_MIDDLE;        // including random.  This doesn't have to
 199      if (NUMBER_OF_THREADS < 11) break;  // make sense.  It just has to work.
 200      s[10][RULE] = ALWAYS_LEAST;
 201      if (NUMBER_OF_THREADS < 13) break;
 202    }
 203  
 204    //  Wait for threads to throw.  Collect results.  Signal threads to throw again.
 205    iteration_count = 0;
 206    record_time();
 207    while (iteration_count++ < NUMBER_OF_ITERATIONS)
 208    {
 209      fprintf(fout,"\n Line 209.  ===================== iteration_count = %4d.",iteration_count);
 210       printf(     "\n Line 209.  ===================== iteration_count = %4d.",iteration_count);
 211      totals[ROCK] = totals[PAPER] = totals[SCISSORS] = 0;  // Initialize TOTALS to zero.
 212  
 213      // For each thread wait for it to throw.  Then accumulate its throw into TOTALS.
 214      for (i=0;i<NUMBER_OF_THREADS;i++)
 215      {
 216        spin_count = 0;
 217        //fprintf(fout,"\n Line 217.  Wait for thred %d.  s[i][THROW] = %d.",i,s[i][THROW]);
 218        // while (s[i][THROW] == NONE) {} // This could replace the next while statement.
 219        while (s[i][THROW] == NONE) if (spin_count++ > MAIN_SPIN_LIM) 
 220        {
 221          fprintf(fout,"\n Line 221. MAIN waiting for thred %3d.  THROW=%d.",i,s[i][THROW]);  // READ SHARED OPERAND.
 222          if (debug) dump(debug);
 223          spin_count = 0;
 224        } 
 225        //fprintf(fout,"\n Line 225.  thred %d.  throw is nonzero.   s[i][THROW] = %d.",i,s[i][THROW]);
 226        totals[s[i][THROW]]++;                                             // READ SHARED OPERAND.
 227      }  //  for (i=0;i<NUMBER_OF_THREADS;i++)
 228  
 229      if (debug) dump(debug); fprintf(fout,"\n Subtot  ");
 230      for (i=0;i<NUMBER_OF_THREADS;i++)  // Update SUM of wins for each thread.
 231      {
 232        temp = s[i][SUM]; 
 233        if (s[i][THROW] == ROCK)     s[i][SUM] += totals[SCISSORS];        // READ SHARED OPERAND.
 234        if (s[i][THROW] == PAPER)    s[i][SUM] += totals[ROCK];            // READ SHARED OPERAND.
 235        if (s[i][THROW] == SCISSORS) s[i][SUM] += totals[PAPER];           // READ SHARED OPERAND.    
 236        fprintf(fout," %4d ", s[i][SUM] - temp);
 237      }
 238        
 239      sort[0]=ROCK; sort[1]=PAPER; sort[2]=SCISSORS;
 240      fprintf(fout,"\n Line 240 sort totals %4d  %4d  %4d        %4d  %4d  %4d  %4d  ",
 241        sort[0],sort[1],sort[2],totals[0],totals[1],totals[2],totals[3]);
 242      if (totals[sort[0]] > totals[sort[1]]) {temp=sort[0]; sort[0]=sort[1]; sort[1]=temp;}
 243      if (totals[sort[1]] > totals[sort[2]]) {temp=sort[1]; sort[1]=sort[2]; sort[2]=temp;}
 244      if (totals[sort[0]] > totals[sort[1]]) {temp=sort[0]; sort[0]=sort[1]; sort[1]=temp;}
 245      fprintf(fout,"\n Line 245 sort totals %4d  %4d  %4d        %4d  %4d  %4d  %4d  ",
 246        sort[0],sort[1],sort[2],totals[0],totals[1],totals[2],totals[3]);     // Now sort[0] says which throw resulted in the least       wins during the last iteration.
 247      // Now sort[1] says which throw resulted in the middlingest wins during the last iteration.
 248      // Now sort[2] says which throw resulted in the most        wins during the last iteration.
 249      // This info is used by some threads to decide their next throw.
 250      
 251      // Signal threads to throw again.
 252      for (i=0;i<NUMBER_OF_THREADS;i++) {s[i][RANDOM] = rand()%3+1; s[i][THROW] = NONE;} // WRITE SHARED OPERANDS.
 253      if (debug) dump(debug);
 254      
 255      record_time();
 256      put_time(SM_DUR,difsc,difms,"noop");
 257      fprintf(fout,"\n  Duration of iteration %2d:  %s.",iteration_count,duration1);  
 258    }  //  while (iteration_count++ < NUMBER_OF_ITERATIONS)
 259   
 260    // Signal threads to stop.
 261    for (i=0;i<NUMBER_OF_THREADS;i++) s[i][THROW] = END;
 262  
 263    // Wait for threads to signal that they have ended.
 264    for (i=0;i<NUMBER_OF_THREADS;i++) while (s[i][THROW] != ENDED) {};     // READ SHARED OPERAND.
 265  
 266    // Print out the results.
 267    fprintf(fout,"\n\n    Results                       Total "
 268                 "\n\n    Thread     Discipline         Wins    \n");
 269    for (i=0;i<NUMBER_OF_THREADS;i++)
 270      fprintf(fout,"\n        %2d     %14s     %4d  ",i, names[s[i][RULE]], s[i][SUM]);
 271  
 272    fprintf(fout,"\n\n  Line 272. MAIN terminating.");
 273    printtd("End execution of Rock, Paper, Scissors.");
 274    nowsc = nowsc - time_test_start_sc;
 275    nowms = nowms - time_test_start_ms;
 276    if (nowms < 0) { nowsc--; nowms += 1000; }
 277    
 278    put_time(DUR,nowsc       ,nowms       ,"Duration of run:");
 279    fprintf(fout,"\n\n"); //  Advance to next line on Linux.
 280  
 281    fflush(fout);
 282    fclose(fout);
 283  
 284    return(0);
 285  
 286  }  // int main() 
 287  
 288  /*===============================================================
 289  *
 290  * THRED.
 291  *
 292  *==============================================================*/
 293  void thred(void* z)
 294  {
 295    int temp1,temp2, i = *(int*)z,spin_count;
 296    fprintf(fout,"\n Line 296. Begin thred %3d.",i);
 297  
 298    spin_count = 0;
 299    while (1)                           
 300    {
 301      if (FETCH == 1) temp1 = temp2 = s[i][THROW];
 302      if (FETCH == 2) {temp1 = s[i][THROW]; temp2 = s[i][THROW];}
 303  
 304      if (temp1 == END ) break;
 305      if (temp2 == NONE)
 306      {
 307        if (s[i][RULE]  == ALWAYS_ROCK     ) s[i][THROW] = ROCK;             // READ AND WRITE SHARED OPERANDS.
 308        if (s[i][RULE]  == ALWAYS_PAPER    ) s[i][THROW] = PAPER;            // READ AND WRITE SHARED OPERANDS.
 309        if (s[i][RULE]  == ALWAYS_SCISSORS ) s[i][THROW] = SCISSORS;         // READ AND WRITE SHARED OPERANDS.
 310        if (s[i][RULE]  == ALWAYS_MOST     ) s[i][THROW] = sort[2];          // READ AND WRITE SHARED OPERANDS.
 311        if (s[i][RULE]  == ALWAYS_MIDDLE   ) s[i][THROW] = sort[1];          // READ AND WRITE SHARED OPERANDS.
 312        if (s[i][RULE]  == ALWAYS_LEAST    ) s[i][THROW] = sort[0];          // READ AND WRITE SHARED OPERANDS.
 313        if (s[i][RULE]  == ALWAYS_RANDOM   ) s[i][THROW] = s[i][RANDOM];     // READ AND WRITE SHARED OPERANDS.
 314        if (debug) fprintf(fout,"\n Line 314. i throw      %2d     %d.",i,s[i][THROW]);
 315        if (s[i][THROW] == NONE)  // Error checking.
 316        {
 317          fprintf(fout,"\n\n THRED.  ERROR.  Line 317.  THROW not set to value other than NONE.");
 318           printf(     "\n\n THRED.  ERROR.  Line 317.  THROW not set to value other than NONE.");
 319        }
 320        continue;
 321      }
 322  
 323      if (spin_count++ < THRD_SPIN_LIM) continue;
 324      fprintf(fout,"\n Line 324. thred %2d spinning.  THROW = %d.",i,s[i][THROW]); 
 325      if (debug) dump(debug);
 326      spin_count=0;
 327    }
 328  
 329    fprintf(fout,"\n  Line 329. thred %3d terminating.",i);
 330    fflush(fout);
 331    s[i][THROW] = ENDED;
 332    return;
 333  }  //  void thred(void* z)
 334  
 335  /*---------------------------------------------------------------
 336  * RECORD_TIME   Record the current time in nowsc & nowms.
 337  *               Record the time duration since 
 338  *                 record_time() was last called in difsc & difms.
 339  *               Record the time since the job began in rel_time.
 340  *--------------------------------------------------------------*/
 341  long record_time()
 342  {
 343    presc = nowsc; prems = nowms;
 344  
 345  #ifdef TIME0
 346    ftime(&tmb);
 347    nowsc = (long)tmb.time - tmb.timezone*60 + tmb.dstflag*3600 - timezero - hour_delta*3600;
 348    nowms = tmb.millitm;
 349  //  newtime = 1000 * (tmb.time - tmb.timezone*60 + tmb.dstflag*3600 - timezero - hour_delta*3600) + tmb.millitm;
 350  #endif
 351  #ifdef TIME2
 352    gettimeofday(&tp,NULL);
 353    nowsc = tp.tv_sec - hour_delta*3600 - timezero;
 354    nowms = tp.tv_usec/1000;
 355  #endif
 356  
 357    difsc = nowsc - presc;
 358    difms = nowms - prems;
 359    if (difms < 0) {difms += 1000; difsc--;}
 360  
 361    rel_time = (nowsc-time_test_start_sc)*1000 + nowms-time_test_start_ms;
 362  
 363    //qddd(2,"\n                                              now = %d.%d  rel_time = %d.",nowsc,nowms,rel_time);
 364  
 365    return(rel_time);
 366  } /* record_time() */
 367  
 368  /*---------------------------------------------------------------
 369  * PRINTTD   Print out the time and the date.
 370  *  Different versions are needed for different systems.
 371  *  Some versions are incomplete (as of 950115) and require that
 372  * hour_delta be set to the difference between GMT and local time.
 373  *
 374  *--------------------------------------------------------------*/
 375  void printtd(char *inchar)
 376  {
 377    record_time();
 378    put_time(TIME,nowsc,nowms,inchar);
 379    return;
 380  } /* printtd() */
 381  
 382  /*---------------------------------------------------------------
 383  * PUT_TIME        Format and print a time/date or duration.
 384  *  TIM/DUR/SM_DUR  Format a time or a duration line, or a duration string.
 385  *  SC       Seconds
 386  *  MS       Milliseconds
 387  *  Z        Character string for an output line.
 388  *--------------------------------------------------------------*/
 389  void put_time(int time, long sc, int ms, char* z)
 390  {
 391    int j,yr=0,mo=0,da=0,days=0,temp;
 392    int damo[] = {0,31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
 393                   396, 424, 455, 485, 516, 546, 577, 608, 638, 669, 699, 730,
 394                   761, 790, 821, 851, 882, 912, 943, 974,1004,1035,1065,1096,
 395                   1127,1155,1186,1216,1247,1277,1308,1339,1369,1400,1430,1461,9999};
 396    char blanks[] = "                                                             ";
 397  
 398    if (sc < 0) fprintf(fout,"\nError#20.  PUT_TIME():  SC = %ld < 0.",sc);
 399  
 400    strcpy(duration1,"00:00:00.000");
 401    j = 60-strlen(z);
 402    if (j < 0) j = 0;
 403    blanks[j] = '\x0';
 404    temp = ms;
 405    duration1[11] = (char)(temp%10+48); temp = temp/10;  // milliseconds.
 406    duration1[10] = (char)(temp%10+48); temp = temp/10;
 407    duration1[ 9] = (char)(temp%10+48); 
 408    temp = sc%86400;                               // = no. of seconds since midnight.   
 409    duration1[ 7] = (char)(temp%10+48); temp = temp/10;  // seconds
 410    duration1[ 6] = (char)(temp% 6+48); temp = temp/ 6;
 411    duration1[ 4] = (char)(temp%10+48); temp = temp/10;  // minutes
 412    duration1[ 3] = (char)(temp% 6+48); temp = temp/ 6;
 413    duration1[ 1] = (char)(temp%10+48); temp = temp/10;  // hours
 414    duration1[ 0] = (char)(temp% 6+48); temp = temp/ 6;
 415    if (time == TIME)           // Calculate year.month.day.    hhh
 416    {
 417      days = sc/86400;          // = no of days since TIMEZERO.
 418      temp = days%1461;
 419      for (mo=1;mo<48;mo++) if (temp < damo[mo]) break;
 420      mo--;
 421      da = temp - damo[mo] + 1;
 422      yr = yearzero + 4*(days/1461) + mo/12;
 423      mo = mo%12+1;
 424    }
 425    else                        // Delete leading zeroes.
 426      for (j=0;j<7;j++)
 427        if ((duration1[j] == '0') || (duration1[j] == ':')) duration1[j] = ' ';
 428        else break;
 429    if (time == SM_DUR) return;
 430  
 431    if (time == DUR) fprintf(fout,"\n%s%s%s",z,blanks,duration1);    // durex
 432    else             fprintf(fout,"\n%s%s%s %02d%02d%02d",z,blanks,duration1,yr%100,mo,da);
 433    duration2 = (yr%100) * 10000 + mo * 100 + da;
 434  
 435    return;
 436  }  //  put_time() 
 437  
 438  
 439  /*===============================================================
 440  *
 441  * DUMP.
 442  *
 443  *==============================================================*/
 444  void dump(int z)
 445  {
 446    if ((z == 1) || (z == 3))
 447      fprintf(fout,"\n   throw  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d ",
 448      s[ 0][THROW],s[ 1][THROW],s[ 2][THROW],s[ 3][THROW],s[ 4][THROW],s[ 5][THROW],
 449      s[ 6][THROW],s[ 7][THROW],s[ 8][THROW],s[ 9][THROW],s[10][THROW],s[11][THROW]);
 450      
 451    if ((z == 2) || (z == 3))
 452    {
 453      fprintf(fout,"\n   sum    %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d  %4d ",
 454          s[ 0][SUM  ],s[ 1][SUM  ],s[ 2][SUM  ],s[ 3][SUM  ],s[ 4][SUM  ],s[ 5][SUM  ],
 455          s[ 6][SUM  ],s[ 7][SUM  ],s[ 8][SUM  ],s[ 9][SUM  ],s[10][SUM  ],s[11][SUM  ]);
 456      fprintf(fout,"  =  %d.",
 457          s[ 0][SUM  ]+s[ 1][SUM  ]+s[ 2][SUM  ]+s[ 3][SUM  ]+s[ 4][SUM  ]+s[ 5][SUM  ]+
 458          s[ 6][SUM  ]+s[ 7][SUM  ]+s[ 8][SUM  ]+s[ 9][SUM  ]+s[10][SUM  ]+s[11][SUM  ]);
 459      fprintf(fout,"\n sorttot  %4d  %4d  %4d        %4d  %4d  %4d  %4d",
 460          sort[0],sort[1],sort[2],totals[0],totals[1],totals[2],totals[3]);
 461    }
 462      
 463    return;
 464  }  //  void dump(int z)
 465