views:

173

answers:

2

I wrote some test code like this which compiled and worked fine...

void threadtest()
{
  HANDLE hThrd;
  DWORD threadId;
  int i;

  for (i = 0;i < 5;i++)
  {
    hThrd = CreateThread(
      NULL,
      0,
      ThreadFunc,
      (LPVOID)i,
      0,
      &threadId );
  }
  // more stuff
}

DWORD WINAPI ThreadFunc(LPVOID n)
{
  // stuff
  return 0;
}

Then I wanted to modify the code to put the ThreadFunc inside a class and then declare an array of those classes. I thought the code should look like this:

class thread_type
{

  public:

  DWORD WINAPI ThreadFunc(LPVOID n)
  {
    // stuff
    return 0;
  }
};

void threadtest()
{
  HANDLE hThrd;
  DWORD threadId;
  int i;
  thread_type *slave;

  slave = new thread_type[5];

  for (i = 0;i < 5;i++)
  {
    hThrd = CreateThread(
    NULL,
    0,
    slave[i].ThreadFunc,
    (LPVOID)i,
    0,
    &threadId );
  }
  // more stuff
}

Unfortunately the compiler complains about the line slave[i].ThreadFunc, I think I may need some special casting but all the permutations I try involving "::" and "&" seem to fail (I'm quite new to C++). The real code has some additional complications which I haven't included for clarity, but I think they are irrelevant.

+1  A: 

The following explains the difference between a pointer to a function and a pointer to a member function C++ FAQ Lite. See section 33.2 which explains why what you are doing is a bad idea.

Jackson
+3  A: 

First problem with the code, that the test class is not descendant of the thread_type. Somehow you need to specify the base class. Second is, if you are passing function pointer, that shouldn't be thiscall type. The solution is typically this:

struct thread
{
  virtual void
  run() = 0;

  static thread_func(void* param)
  {
    thread* pThread = (thread*)param;
    thread->run();
  }
}


struct worker : public thread
{
  void
  run()
  {
    (.. code for the thread...)
  }
}

void threadtest()
{
  HANDLE hThrd;
  DWORD threadId;
  int i;
  thread *slave;

  slave = new thread_type[5];
  slave[0] = new worker;
  slave[1] = new worker;
  slave[2] = new worker;
  slave[3] = new worker;
  slave[4] = new worker;

  for (i = 0;i < 5;i++)
  {
    hThrd = CreateThread(
    NULL,
    0,
    &thread::thread_func,
    (LPVOID)slave[i],
    0,
    &threadId );
  }
  // more stuff
}

Note that this could is just a reflection, I couldn't compile now, because I don't have here anything to do so, but the logic should be like this.

progician
Sorry, I wrote test where it should have been thread_type
Mick
If you are passing a function pointer you can't provide the "this" pointer because it's specific to the instance. The method calls are expecting an additional parameter what you can't see on the formal parameter list, that's the this pointer to the object. Since we don't have that, we make a workaround to pass parameter to the actual thread function, the pointer to the object. In the thread function (beware of the pointer type!!) you can cast it to the thread class pointer, containing a virtual function table, so it can choose the right behaviour depending on the object type.
progician
With all do respect, I don't really get, why is the answer just a simple: "you are doing wrong according this link" type, however my answer, where I posted a possible solution and I tried to explain on your example, why is it wrong, doesn't worth it.
progician
Sorry to progician. I marked the other answer as correct because the link was to an established article so I had the confidence to know it was correct. You said yourself that you could not check the correctness of your answer. Having read the (very specific) article, I quickly got my code working. Also your code looks a tiny bit more complicated than the solution I ended up with. I appreciate the time you spent on your answer.
Mick