#include <cassert>
#include <fstream>
#include <iostream>
#include <strstream>


#include <vector>
#include <time.h>


//This is here for the Windows threads.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#define THREADFUNCTIONRETURN DWORD WINAPI


long int gCtr = 0;


using namespace std;


void transform()
{
    for (int i=0; i<100; i++)
        gCtr++;

    cout << "\n   + gCtr = " << gCtr << " ";
}


// Print messages tracking the progress of each thread, and the
// beginning and end of the entire operation.
void outputMessage(DWORD id, char msg[])
{
        ostrstream threadMsg;
    
        threadMsg << "\n" << msg << " Thread: " << id << '\0';
        cout << threadMsg.str();
        threadMsg.freeze(false);
}


THREADFUNCTIONRETURN theThread(LPVOID param)
{
    const int   number = reinterpret_cast<int>(param);
    const DWORD theThreadID = GetCurrentThreadId();

    outputMessage(theThreadID,"\nTransforming");

    transform();

    outputMessage(theThreadID,"   Finishing");
    return (0);
}

// Create and run the threads...
// Print messages tracking the progress of each thread and of the 
// overall operation...
void doThreads(int x)
{
    DWORD dwStackSize = 4096;               // initial thread stack size
    LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)theThread;
    DWORD dwCreationFlags = 0;              // creation flags
    int nThreads = x;

    std::vector<HANDLE> hThreads;
    hThreads.reserve(nThreads);
    int i = 0;
    
    try
    {
        cout << endl << "Clock before starting threads: " << clock();

        for (i=0; i< nThreads; i++)
        {
            HANDLE hThread;
            DWORD  threadID;

            hThread = CreateThread(
                    0, dwStackSize,
                    lpStartAddress,                 // pointer to thread function
                    reinterpret_cast<LPVOID>(i),    // argument for new thread
                    dwCreationFlags,                // creation flags
                    &threadID);
            assert(hThread != 0);
            hThreads.push_back(hThread);
        }

        WaitForMultipleObjects(hThreads.size(), &hThreads[0], TRUE, INFINITE);

        cout << endl << endl << "Clock after threads: " << clock() << endl;

        for (i = 0; i < nThreads; ++i)
        {
            CloseHandle(hThreads[i]);
        }
    }
    catch(...)
    {
        cerr << "Exception caught!!!"
             << endl
             << endl;
    }
}


int main(int argc, const char*  /* argv */[])
{

    if (argc != 1)
    {
        cerr << "Usage: ThreadTest" << endl;
    }
    else
    {
        try
        {
            // init app if needed...

            {
                doThreads(10);
            }

            // terminate app if needed...
        }
        catch(...)
        {
            cerr << "Exception caught!!!" << endl;
        }
    }

    return 0;
}
