2

Reposting this since my prev question got closed..I've tried to explain it better this time...pls let me know if u need further clarifications:

I have a class A with a function doSomething(int count) Within class A, I want to open 100 threads each of which call the function doSomething() and pass in the count 1-100 in each thread.

Which means...when the 1st thread calls this function, it should call doSomething(1), 2nd thread should call doSomething(2) and so on...

This is what my code looks like:

struct input {
  A* in;
  int count;
};


myFunc(void* data)
{
  input* tP = (input*) data;
  A* obj = tP->in;
  int ct = tP->count;
  obj->doSomething(ct);
}

class A {
  doSomething(int count);
  Thread2doSomething();
}

doSomething(int count)
{
  cout<<"Print value is"<<count;
}

Thread2doSomething()
{
   for (i = 1 to 100)
   {
      input myIN;
      myIN.in = this;
      myIN.count = i;
      beginthreadex(myFunc, &myIN);
   }
 }

I expect that the above code will spawn 100 threads here..each of which will have a new value of count 1,2,3...100 when it calls doSomething();

each invocation of doSomething on a new thread should have a different value of count passed to it - 1,2,3,...to 100.

But that does not happen. The count values passed to it are pretty random...often it gets the same value multiple times...and does not get some values at all.Sometimes the value of count passed to doSomething is the same in all the threads...

the calls looks more like this: doSOmething(4),doSomething(4),doSomething(7),doSomething(10),doSomething(10) and so on.

Hope I've clarified things...pls advise.

Omi
  • 976
  • 2
  • 20
  • 35
  • You need to do some serious reading on the concept of race conditions and thread synchronization. This is not so much a programming question as it is a topic of programming that you are as of yet unfamiliar with. – Mahmoud Al-Qudsi Jan 17 '13 at 08:44
  • 1
    is that the actual code? i doubt your class definition will compile – Andy Prowl Jan 17 '13 at 08:46
  • @AndyProwl: No - this is pseudo-code. doSomething and ThreaddoSomething are a part of that class...again have just shown relevant stuff from the code..it definitely compiles...have been using this code for a long time..with no issues except this issue with multiple threads. – Omi Jan 17 '13 at 08:50
  • possible duplicate of [Issue in \_beginthreadex()](http://stackoverflow.com/questions/14321021/issue-in-beginthreadex) – Tadeusz Kopec for Ukraine Jan 17 '13 at 08:53

2 Answers2

2

There are two problems with your code.

The first problem is in the Thread2doSomething() function: you pass the address of a temporary to beginthreadex(). The temporary goes out of scope when the function exits, and threads are accessing an object which does not exist anymore.

You have two possibilities for fixing this : either you wait for all the threads to complete before exiting from Thread2DoSomething(), so that your stack-allocated object won't get destroyed before threads have done their job, or you allocate the input of each thread on the heap (but don't forget to deallocate them if you use raw pointers).

The second problem is that you are passing the same input to all threads and modify it while they are accessing it (inside the for loop), which introduces a data race. Because of this, your program has Undefined Behavior.

To fix this, you must create a new instance of input for each thread, so that you won't overwrite the same object while threads will try to access it.

Finally, keep in mind that there is no guarantee about the order of execution of your threads. Even if you start them in a certain order, you might still see a permutation of your numbers being printed out rather than the ordered sequence 1..100.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
0

You're re-using one instance of input for all the threads. Of course they grab random data from it. Since you can't change the signature of myFunc() (I presume it's mandated by the thread creation function), you'll have to use dynamic allocation:

Thread2doSomething()
{
   input *myIN;
   for (i = 1 to 100) {
     myIN = new input;
     myIN->in = this;
     myIN->count = i;
     beginthreadex(myFunc, myIN);
   }
}

myFunc(void* data)
{
  std::unique_ptr<input> tP(reinterpret_cast<input*>(data));
  A* obj = tP->in;
  int ct = tP->count;
  obj->doSomething(ct);
}

Using unique_ptr in myFunc() will ensure the object gets deallocated when myFunc() terminates.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Sorry - one small mistake - I create a new instance of input within the loop....so for every 'i', I create a new input struct...which takes in this and the value of 'i' as count. – Omi Jan 17 '13 at 08:53
  • @techieChamp If you "create" that instance on the stack (that is, just declaring it `input myIN;`), it's still a temporary (and probably even occupies the same place in memory). There's no guarantee the started thread will run before the main thread overwrites it in the next iteration. You should probably read up on static vs. dynamic storage duration in a [good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Angew is no longer proud of SO Jan 17 '13 at 08:56
  • @techieChamp: so please post your **real** code. how are we supposed to help you with a problem that is not described correctly by your question? do you create this object on the stack or on the heap? it's hard to tell if we can trust your pseudo-code at this point – Andy Prowl Jan 17 '13 at 08:57