0

我有以下代码:

#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调用另一个虚拟方法,但是如果我创建一个具有虚拟方法的其他实现的派生类,多态性似乎不起作用。

为什么?我怎样才能解决这个问题?

编辑:我更新了代码,所以线程没有在构造函数中启动。

4

2 回答 2

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 );
        }
    }
};

然后让你的BaseClassDerivedClass派生自 Threadable,并将它们调用为:

Thread base( std::auto_ptr<Threadable>( new BaseClass ) );
Thread derived( std::auto_ptr<Threadable>( new DerivedClass ) );

这并不完美(我不喜欢析构函数中或多或少的无限等待),但它应该足以开始。(对上面代码中的任何拼写错误进行取模——我还没有测试过。)

于 2013-02-18T11:55:27.090 回答
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!
于 2013-02-18T11:53:41.900 回答