2011-10-18 4 views
4

私は基本クラスと派生クラスを持っています。 彼らは仮想関数を持っていますvirtual void action() どうすれば* pthread_create()*関数に渡すことができますか?C++:(のpthreadライブラリに)スレッドために開始ルーチンとしてクラスメソッドを定義する方法

(エラーのある)例:

class Base{ 
    protected: 
    pthread_t tid; 
    public: 
    virtual void* action() = 0; 
}; 

class Derived : public Base{ 
    void* action(); 
    Derived(){ 
    pthread_create(&tid, NULL, &action, NULL); 
    } 
}; 

多分それは静的である必要がありますか? 私は組み合わせの多くを試みたが、解決策を見つける傾ける。..

+3

おそらく、あなたは 'boost :: thread'や' std :: thread'(C++ 11の) – PlasmaHH

答えて

4

は、ここで簡単な実装(TESTED NOT)です。基本的なC++の仕組みに関する知識が必要です。

基本的な問題は、関数へのポインターがメンバー関数のポインターと異なることです。これは、メンバ関数が暗黙の最初のパラメータthisを持つためです。 manページから

int pthread_create(pthread_t *thread, 
        const pthread_attr_t *attr, 
        void *(*start_routine) (void *), 
        void *arg); 

スレッドの入口点はvoid* (*)(void*)です。あなたの関数Base::actionのタイプはvoid* (Base::*)()です。その醜い型の宣言のBase::部分は、thisの型を示します。型の不一致は、コンパイラがあなたのコードを受け入れない理由です。

この問題を解決するには、2つのことを解決する必要があります。メンバー関数へのポインタは、thisをインスタンスにバインドしないため、メンバー関数を使用することはできません。タイプvoid*の単一のパラメータも必要です。ありがたいことに、解決策は明らかにthisを自分自身に渡すことであるため、これらの2つの修正は手元にあります。

class Base { 
public: 
    virtual void* action() = 0; 

protected: 
    pthread_t tid; 

    friend void* do_action(void* arg) { 
     return static_cast<Base*>(arg)->action(); 
    } 
}; 

class Derived : public Base { 
public: 
    Derived() { 
     // This should be moved out of the constructor because this 
     // may (will?) be accessed before the constructor has finished. 
     // Because action is virtual, you can move this to a new member 
     // function of Base. This also means tid can be private. 
     pthread_create(&tid, NULL, &do_action, this); 
    } 

    virtual void* action(); 
}; 

編集: Woops tidprotectedprivateであれば、その後、do_actionfriendする必要があります。

+0

ポインタをアクションに渡すにはどうすればいいですか?もし必要ならば? void * func(void * p) –

0

は、静的実際に動作することが保証されていませんが、実際には、少なくともほとんどの実装(および十分な人々と私は少しびっくりするだろうと、それに依存しない作りすぐにその変化を見ることもできます)。

+0

を使うべきでしょうか?「静的な」動作が保証されていない理由を詳しく説明できますか? – Arkadiy

+0

@Arkadiy:簡単に言えば、それは働くことが保証されていると言うことは何もないからです。 –

+0

@Jerryあなたはそれがうまくいくという保証を与えると期待しているもののように、さらに詳しく説明できますか? C言語で書かれコンパイルされたスレッドライブラリは、まったく動作することが保証されているとは言えませんが、それでも動作します。 –

2

実際、静的でなければなりません。あなたはpthread_createのための引数として、あなたのオブジェクトを渡すことも必要があります:

void *Base::static_action(void *v) 
{ 
    ((Base*)v)->action(); 
    return NULL; 
} 

pthread_create(&tid, NULL, &Base::static_action, myObject); 
3

あなたはpthread_createに渡す1のvoidポインタをとる関数を持っている必要があります。私は、BaseDerivedも同様に動作する)へのポインタをとる関数として、自分自身で関数を記述し、次にパラメータのaction関数を呼び出します。あなたは、その関数を実行するスレッドを作成し、パラメータとしてthisを受信することができます:私は通常、これに似た何かを

void *f(void *param) 
{ 
    Base* b = (Base *)param; 
    return b->action(); 
} 

class Derived : public Base{ 
    void* action(); 
    Derived() { 
    pthread_create(&tid, NULL, f, this); 
    } 
}; 
1

、私はあなたが(エラー処理、ロック、など)その他の詳細を記入してもらおう:

Startメソッド:

bool pthreadBase::start() 
{ 
    return pthread_create(&threadID, NULL, &execute,this); 
} 

静的void *型Executeメソッド:

void *pthreadBase::execute(void *t) 
{ 
    reinterpret_cast<pthreadBase *> (t)->processLoop(); 
    return NULL; 
} 

その後、スレッドのエントリポイントとして機能するprocessLoopという仮想メソッドを作成できます。私は戻って私のシニア設計プロジェクトに取り組んで数ヶ月、この問題に遭遇した

class theThread: public pthreadBase 
{ 
    public: 
     theThread(SharedMemoryStructure *SharedMemory) 
     { 
     _Running = start(); 
     _Shared = SharedMemory; 
     } 

     ~theThread() 
     { 
     stop(); //Just do a join or something 
     _Running = false; 
     } 

    private: 
     void processLoop() 
     { 
     while(_Shared->someQuitFlag() == false) 
     { 
      /*Do Work*/ 
     } 
     } 

    private: 
     bool _Running; 
     SharedmemoryStructure *_Shared; 
}; 
関連する問題