/* ------------------------------------------------------------------------
 *                         TestBoundedBuffer.cpp
 * ------------------------------------------------------------------------
 *   Test driver for the BoundedBuffer synchronization classes.
 *
 *  Copyright 1997-1998 by G. Wade Johnson (Telescan, Inc.)
 *   Use of this code is placed in the public domain as long as the
 *   copyright notice is retained.
 */

#include <windows.h>
#include <iostream>
#include "BoundedBuffer.h"
#include "Event.h"


const unsigned BufferSize   = 5;
const unsigned NumConsumers = 8;
const unsigned NumProducers = 2;

class ProtectedBuffer
 {
  unsigned        mySize;
  unsigned        myNumItems;
  long           *mypBuffer;
  BoundedBuffer   myProtect;

public:
  ProtectedBuffer( unsigned size )
   : mySize(size), myNumItems(0), mypBuffer(0), myProtect(BufferSize)
   {
    mypBuffer = new long[size];
    for(unsigned i=0;i < mySize;++i)
      mypBuffer[i] = 0;
   }
  ~ProtectedBuffer() { delete mypBuffer; mypBuffer = 0; }

  void  Push( long value );
  long  Pop();
 } ;

void  ProtectedBuffer::Push( long value )
 {
  BBProducer  prot(myProtect);
  mypBuffer[myNumItems++] = value;
 }

long  ProtectedBuffer::Pop()
 {
  BBConsumer  prot(myProtect);
  return mypBuffer[--myNumItems];
 }


ProtectedBuffer   Buff(BufferSize);
AutoResetEvent    LockStep;   // Used to reduce startup conflicts

DWORD  WINAPI  ConsumeThread( LPVOID lpvBB );
DWORD  WINAPI  ProduceThread( LPVOID lpvBB );

int main( void )
 {
  HANDLE         Threads[2];
  DWORD          Dummy;
  int            ThreadNum=0;
  int            i;

  LockStep.Reset();
  Threads[0] = CreateThread( NULL, 0, ConsumeThread, NULL, 0, &Dummy );
  LockStep.Wait();
  Threads[1] = CreateThread( NULL, 0, ProduceThread, NULL, 0, &Dummy );
  LockStep.Wait();
  ThreadNum = 2;

  for(i=0;i < ThreadNum;++i)
   {
    WaitForSingleObject( Threads[i], INFINITE );
   }

  Sleep( 5000 );

  return 0;
 }


DWORD  WINAPI  ConsumeThread( LPVOID )
 {
  unsigned         i;

  LockStep.Set();   // Release main thread

  cout << "First Consume: " << Buff.Pop() << endl;

  for(i=0;i < BufferSize-1;++i)
    cout << "Consume: " << Buff.Pop() << endl;

  Sleep( 5000 );

  for(i=0;i < BufferSize;++i)
    cout << "Consume: " << Buff.Pop() << endl;

  cout << "Consume: " << Buff.Pop() << endl;

  return 0L;
 }



DWORD  WINAPI   ProduceThread( LPVOID )
 {
  unsigned         i;
  long             in=0L;

  LockStep.Set();   // Release main thread

  Sleep( 2000 );

  for(i=0;i < 2*BufferSize;++i)
    Buff.Push( ++in );

  cout << "Last one ...";
  Buff.Push( ++in );
  cout << "Completed." << endl;

  return 0L;
 }
