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

派生オブジェクトの構築が完了する前に、スレッドを開始しています。これは未定義の動作です (作成スレッドでコードを実行している間に、新しいスレッドでオブジェクトにアクセスする可能性が高いため)。構築とスレッドの開始を分離する必要があります。

編集:

この種の問題を処理する 1 つの方法:

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 に答える