views:

80

answers:

3

Hi. I'm just beginning to learn C++ and I'm trying to make Thread class that that has the basic functionality of the Java Thread class. What I'm trying to do is make a class which you subclass, write a Run method (which is pure virtual in the base class) create an object of the subclass call the start method on it and you have thread.

The problem is that in the way I use C++ the dispatch isn't done correctly - it's like the Run function isn't virtual, the Run method of the base class is called.

Here is the code for the header

#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>

class Thread {
 public:
  Thread();

  void Start();

  ~Thread();

 protected:
  virtual void Run() = 0;

 private:
  static void *RunWrapper(void *);

  pthread_t thread;
};

#endif

The implementation

#include "thread.h"

#include <pthread.h>

Thread::Thread() {
}

void Thread::Start() {
  pthread_create(&thread, NULL, Thread::RunWrapper, (void *) this);
}

void *Thread::RunWrapper(void *arg) {
  Thread *t = (Thread *) arg;
  t->Run();
  return arg;
}

Thread::~Thread() {
  pthread_join(thread, NULL);
}

And the file that actually tries to do something

#include <iostream>

#include "thread.h"

class MyThread : public Thread {
 protected:
  void Run() {
    std::cout << "The thread is runned" << std::endl;
  }
};

int main(void) {
  MyThread thread;
  thread.Start();
  return 0;
}

The error I keep getting for the last 10 hours is:

pure virtual method called
terminate called without an active exception

Thank you!

A: 

Not certain what's causing the error directly, but what you're doing is bad: your MyThread object can go out of scope before your thread accesses it. It's entirely possible the scope is gone and the pointer is invalid by the time your thread starts processing.

Try allocating your object on the heap, and see if it works (then, assuming it does, figure out how to free the object when the thread is done).

Oh, and you'll want to next exit your app (by returning from main) until your thread is done also...

Nick
I fixed it using a synchronization mechanism. Thanks!
John B.
Well, it won't be totally gone, because of the call to `pthread_join` in `Thread::~Thread()`. But when `Thread::~Thread` runs, the object has already lost its identity as a derived class (the derived destructor has already run) -- during destruction virtual methods are called non-virtually.
Ben Voigt
+5  A: 

The problem is that your MyThread object in main is destroyed as soon as the main function returns, which likely happens before the new thread actually gets around to calling its Start method.

As part of the destruction process, the vtable will be reset to the vtable of the base class before calling the base class destructor, so when the RunWrapper call later gets run it ends up triggering the pure virtual method error. Calling a method on a destroyed object results in undefined behavior, so anything might happen; this behavior is an accident of how your C++ compiler implements destructors and stack allocation.

Chris Dodd
Yes, this was the problem. Thanks a lot! When learning a new language one thinks all the problems are generated by the language :).
John B.
A: 

The problem is that you are calling Start, which belongs to the Thread class. This method is then calling Run, which will call the Run method of the Thread class. Unfortunately, you cannot call the overrided method from the base class.

Alexander Rafferty
This is not correct; that's exactly what virtual methods do.
Nick
You cannot call them from within the base class methods.
Alexander Rafferty
I can call Run on the subclass because I use a pointer and the method is virtual.
John B.
seems you can. Then why are you getting the virtual method errors?
Alexander Rafferty