0

following some former advice Multithreaded application, am I doing it right?

I think I have a threadsafe number generator using boost, but my program crashes when I input 1000 iterations. The output .csv file when graphed looks right, but I'm not sure why it's crashing.

It's using _beginthread, and everyone is telling me I should use the more (convoluted) _beingthreadex, which I'm not familiar with. If someone could recommend an example, I would greatly appreciate it.

Also... someone pointed out I should be applying a second parameter to my _beginthread for the array counting start positions, but I have no idea how to pass more than one parameter, other than attempting to use a structure, and I've read structure's and _beginthread don't get along (although, I could just use the boost threads...)

#include <process.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <time.h>
#include <random>
#include <boost/random.hpp>

//for srand48_r(time(NULL), &randBuffer); which doesn't work
#include <stdio.h>
#include <stdlib.h>

//#include <thread>

using namespace std;
using namespace boost;
using namespace boost::random;

void myThread0 (void *dummy );
void myThread1 (void *dummy );
void myThread2 (void *dummy );
void myThread3 (void *dummy );

//for random seeds
void initialize();

    //from https://stackoverflow.com/questions/7114043/random-number-generation-in-c11-how-to-generate-how-do-they-work
    uniform_int_distribution<> two(1,2);

    typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters

    uint32_t seed_val;           // populate somehow

    MyRNG rng1;                   // e.g. keep one global instance (per thread)
    MyRNG rng2;                   // e.g. keep one global instance (per thread)
    MyRNG rng3;                   // e.g. keep one global instance (per thread)
    MyRNG rng4;                   // e.g. keep one global instance (per thread)

//only needed for shared variables
//CRITICAL_SECTION cs1,cs2,cs3,cs4; // global

int main()
{

    ofstream myfile;
    myfile.open ("coinToss.csv");

    int rNum;

    long numRuns;
    long count = 0;
    int divisor = 1;
    float fHolder = 0;
    long counter = 0;
    float percent = 0.0;

    //?
    //unsigned threadID;

    //HANDLE hThread;

    initialize();

    HANDLE hThread[4];

    const int size = 100000;

    int array[size];

    printf ("Runs (uses multiple of 100,000) ");
    cin >> numRuns;

    for (int a = 0; a < numRuns; a++)
     {

            hThread[0] = (HANDLE)_beginthread( myThread0, 0, (void*)(array) );
            hThread[1] = (HANDLE)_beginthread( myThread1, 0, (void*)(array) );
            hThread[2] = (HANDLE)_beginthread( myThread2, 0, (void*)(array) );
            hThread[3] = (HANDLE)_beginthread( myThread3, 0, (void*)(array) );

            //waits for threads to finish before continuing
            WaitForMultipleObjects(4, hThread, TRUE, INFINITE);

            //closes handles I guess?
            CloseHandle( hThread[0] );
            CloseHandle( hThread[1] );
            CloseHandle( hThread[2] );
            CloseHandle( hThread[3] );

        //dump array into calculations
        //average array into fHolder

            //this could be split into threads as well
            for (int p = 0; p < size; p++)
             {
                counter += array[p] == 2 ? 1 : -1;
                //cout << array[p] << endl;
                //cout << counter << endl;
            }

            //this fHolder calculation didn't work
            //fHolder = counter / size;

            //so I had to use this
            cout << counter << endl;
            fHolder = counter;
            fHolder = fHolder / size;

            myfile << fHolder << endl;

    }
}

    void initialize()
    {

      //seed value needs to be supplied
      //rng1.seed(seed_val*1);

      rng1.seed((unsigned int)time(NULL));
      rng2.seed(((unsigned int)time(NULL))*2);
      rng3.seed(((unsigned int)time(NULL))*3);
      rng4.seed(((unsigned int)time(NULL))*4);
    };


void myThread0 (void *param)
{
    //EnterCriticalSection(&cs1); //aquire the critical section object

    int *i = (int *)param;

    for (int x = 0; x < 25000; x++)
    {
        //doesn't work, part of merssene twister
        //i[x] = next();
        i[x] = two(rng1);

        //original srand
        //i[x] = rand() % 2 + 1;

        //doesn't work for some reason.
        //uint_dist2(rng);

        //i[x] = qrand() % 2 + 1;
        //cout << i[x] << endl;
    }
    //LeaveCriticalSection(&cs1); // release the critical section object

}

void myThread1 (void *param)
{
    //EnterCriticalSection(&cs2); //aquire the critical section object

    int *i = (int *)param;

    for (int x = 25000; x < 50000; x++)
    {
        //param[x] = rand() % 2 + 1;
        i[x] = two(rng2);
        //i[x] = rand() % 2 + 1;
        //cout << i[x] << endl;
    }
    //LeaveCriticalSection(&cs2); // release the critical section object

}

void myThread2 (void *param)
{
    //EnterCriticalSection(&cs3); //aquire the critical section object

    int *i = (int *)param;

    for (int x = 50000; x < 75000; x++)
    {
        i[x] = two(rng3);
        //i[x] = rand() % 2 + 1;
        //cout << i[x] << endl;
    }
    //LeaveCriticalSection(&cs3); // release the critical section object

}

void myThread3 (void *param)
{
    //EnterCriticalSection(&cs4); //aquire the critical section object

    int *i = (int *)param;

    for (int x = 75000; x < 100000; x++)
    {
        i[x] = two(rng4);
        //i[x] = rand() % 2 + 1;
        //cout << i[x] << endl;
    }
    //LeaveCriticalSection(&cs4); // release the critical section object

}
Community
  • 1
  • 1
thistleknot
  • 1,098
  • 16
  • 38
  • 1
    Can you reduce this code to the shortest complete snippet that exhibits the problem, and then post that? The less code there is to debug, the easier it will be to find the problem. – Adam Liss Oct 14 '12 at 03:44
  • 1
    ^^^ and show us the line that crashes. You have commented out code and a lot of other stuff that isn't relevant. It is unreasonable to expect us to wade through all of that. – Ed S. Oct 14 '12 at 03:48
  • Passing a struct/class instance to _beginthread is just fine, you just have to ensure that each thread gets its own by creating a separate one for each thread instance with new/malloc/whatever. Problems only arise when developers use auto/stack-based structs/classes. – Martin James Oct 14 '12 at 09:31

1 Answers1

0

This isn't really an answer to the issue exactly (I did read that _beginThread is prone to memory leaks), but I did create a v5 that used only boost threads (commented lines removed). Btw, I have no idea where it was crashing

#include <process.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <time.h>
#include <random>
#include <boost/thread.hpp>
#include <boost/random.hpp>

//for srand48_r(time(NULL), &randBuffer); which doesn't work
#include <stdio.h>
#include <stdlib.h>

//#include <thread>

using namespace std;
using namespace boost;
using namespace boost::random;

//for random seeds
void initialize();
void workerFunc1(void *dummy );
void workerFunc2(void *dummy );
void workerFunc3(void *dummy );
void workerFunc4(void *dummy );

    //from http://stackoverflow.com/questions/7114043/random-number-generation-in-c11-how-to-generate-how-do-they-work
    uniform_int_distribution<> two(1,2);

    typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters

    uint32_t seed_val;           // populate somehow

    MyRNG rng1;                   // e.g. keep one global instance (per thread)
    MyRNG rng2;                   // e.g. keep one global instance (per thread)
    MyRNG rng3;                   // e.g. keep one global instance (per thread)
    MyRNG rng4;                   // e.g. keep one global instance (per thread)

//only needed for shared variables
//CRITICAL_SECTION cs1,cs2,cs3,cs4; // global

int main()
{

    ofstream myfile;
    myfile.open ("coinToss.csv");

    int rNum;

    long numRuns;
    long count = 0;
    int divisor = 1;
    float fHolder = 0;
    long counter = 0;
    float percent = 0.0;

    //?
    //unsigned threadID;

    //HANDLE hThread;

    initialize();

    HANDLE hThread[4];

    const int size = 100000;

    int array[size];

    printf ("Runs (uses multiple of 100,000) ");
    cin >> numRuns;

    for (int a = 0; a < numRuns; a++)
     {

            thread workerThread1(workerFunc1, (void*)(array) );
            thread workerThread2(workerFunc2, (void*)(array) );
            thread workerThread3(workerFunc3, (void*)(array) );
            thread workerThread4(workerFunc4, (void*)(array) );


            //waits for threads to finish before continuing
            workerThread1.join();
            workerThread2.join();
            workerThread3.join();
            workerThread4.join();

            //dump array into calculations
            //average array into fHolder

            //this could be split into threads as well
            for (int p = 0; p < size; p++)
             {
                counter += array[p] == 2 ? 1 : -1;
                //cout << array[p] << endl;
                //cout << counter << endl;
            }

            //this fHolder calculation didn't work
            //fHolder = counter / size;

            //so I had to use this
            //cout << counter << endl;
            fHolder = counter;
            fHolder = fHolder / size;

            myfile << fHolder << endl;

    }
}

    void initialize()
    {

      //seed value needs to be supplied
      //rng1.seed(seed_val*1);

      rng1.seed((unsigned int)time(NULL));
      rng2.seed(((unsigned int)time(NULL))*2);
      rng3.seed(((unsigned int)time(NULL))*3);
      rng4.seed(((unsigned int)time(NULL))*4);
    };

//recieves array, and spot of array to work on,
void workerFunc1(void *param)
{

    int *i = (int *)param;

    for (int x = 0; x < 25000; x++)
    {
        //gets a random 1 or 2 value
        i[x] = two(rng1);
        //converts to -1 or +1, then adds it to sum (I would love to combine these two)
    }
    //return sum;
}

void workerFunc2(void *param)
{

    int *i = (int *)param;

    for (int x = 25000; x < 50000; x++)
    {
        //gets a random 1 or 2 value
        i[x] = two(rng2);
        //converts to -1 or +1, then adds it to sum (I would love to combine these two)
    }
    //return sum;
}

void workerFunc3(void *param)
{

    int *i = (int *)param;

    for (int x = 50000; x < 75000; x++)
    {
        //gets a random 1 or 2 value
        i[x] = two(rng3);
        //converts to -1 or +1, then adds it to sum (I would love to combine these two)
    }
    //return sum;
}

void workerFunc4(void *param)
{


    int *i = (int *)param;

    for (int x = 75000; x < 100000; x++)
    {
        //gets a random 1 or 2 value
        i[x] = two(rng4);
        //converts to -1 or +1, then adds it to sum (I would love to combine these two)
    }
    //return sum;
}
thistleknot
  • 1,098
  • 16
  • 38