我有以下代码:
#include <windows.h>
#include <iostream>
static DWORD __stdcall startThread(void *);
class BaseClass {
private:
void threadLoop() {
// stuff ...
std::cout << someStuff() << std::endl;
// stuff ...
}
protected:
HANDLE handle;
virtual int someStuff() {
return 1;
}
public:
friend DWORD __stdcall startThread(void *);
BaseClass() {
handle = 0;
};
void start() {
handle = CreateThread(NULL, 0, startThread, this, 0, NULL);
}
~BaseClass() {
if(handle != 0) {
WaitForSingleObject(handle, INFINITE);
CloseHandle(handle);
}
}
// stuff
};
static DWORD __stdcall startThread(void *obj_) {
BaseClass *obj = static_cast<BaseClass *>(obj_);
obj->threadLoop();
return 0;
}
class DerivedClass : public BaseClass {
public:
virtual int someStuff() {
return 2;
};
};
int main() {
BaseClass base;
base.start();
DerivedClass derived;
derived.start();
}
每个实例使用WINAPI和帮助函数startThread
创建一个线程,该函数将调用委托给创建线程的对象的方法threadLoop
。现在的问题是threadLoop
调用了另一个虚方法,但如果我用其他实现的虚方法创建一个派生类,那么多态似乎不起作用。
为什么呢?我该如何解决这个问题?
编辑:我更新了代码,因此线程无法在构造函数中启动。
答案 0 :(得分:6)
你在完成构建之前就开始了 派生对象。这是未定义的行为(因为你会 你可能正在访问新主题中的对象 仍然在创建线程中执行代码)。你必须这样做 单独的构造和启动线程。
编辑:
处理此类问题的一种方法:
class Threadable
{
public:
virtual Threadable() {}
virtual run() = 0;
};
DWORD __stdcall startThread( void* object )
{
static_cast<Threadable*>( object )->run();
}
class Thread
{
std::auto_ptr<Threadable> myThread;
HANDLE myHandle;
public:
Thread( std::auto_ptr<Threadable> thread )
: myThread( thread )
, myHandle( CreateThread( NULL, 0, startThread, myThread.get(), 0, NULL ) )
{
}
~Thread()
{
if ( myHandle != NULL ) {
WaitForSingleObject( myHandle, INFINITE );
CloseHandle( myHandle );
}
}
};
然后让您的BaseClass
和DerivedClass
派生自
Threadable
,并将其调用为:
Thread base( std::auto_ptr<Threadable>( new BaseClass ) );
Thread derived( std::auto_ptr<Threadable>( new DerivedClass ) );
这并不完美(我不喜欢或多或少无限制的等待 析构函数),但它应该足以开始。 (模 上面代码中的任何拼写错误 - 我都没有测试过。)
答案 1 :(得分:1)
您的代码存在一些问题,例如您在构造对象时正在创建和运行线程。这绝对是一个糟糕的设计。
一个简洁的设计是将线程功能封装在一个名为thread
的抽象类中,然后从中派生,覆盖run
方法,例如:
class thread : public noncopyable
{
protected:
HANDLE m_hthread;
unsigned long m_id;
private:
static unsigned long __stdcall start(void* args)
{
static_cast<thread*>(args)->run();
return 0;
}
public:
thread();
virtual ~thread();
virtual bool start()
{
if ( m_hthread != nullptr && isrunning(m_hthread) )
{
throw std::logic_error("Cannot start thread, as it is already running.");
}
m_hthread = ::CreateThread(NULL, 0, start, this, 0, &m_id);
return m_hthread != nullptr;
}
unsigned long get_id() const;
virtual unsigned long wait();
protected:
virtual void run() = 0;
};
从中衍生出来:
class worker : public thread
{
protected:
virtual void run() override;
};
你会用它作为:
worker workerObject;
workerObject.start();
//do other works here
//maybe create few more threads;
workerObject.wait(); //wait for worker to complete!