2009-07-20 10 views
67

のは、私は、このようなpthreadの機能

class c { 
    // ... 
    void *print(void *){ cout << "Hello"; } 
} 

としてクラスを持っている。そして、私はC

vector<c> classes; pthread_t t1; 
classes.push_back(c()); 
classes.push_back(c()); 

のベクトルを持っているとしましょう、私はc.print();

にスレッドを作成したいです

そして、以下は私に以下の問題を与えています:pthread_create(&t1, NULL, &c[0].print, NULL);

エラー出力リレー:引数に '*空 ()(ボイド)' に 'ボイド*(tree_item :: )(無効)' に変換することはできません '3' int型のpthread_create(がpthread_t *、constの のpthread_attr_t」へ*、

答えて

125

C++クラスメンバ関数に隠されたパラメータが渡されているので、それを書いたようにしてください。pthread_create()は、thisのどの値を使用するのか分かりません。そのため、メソッドを関数ポインタにキャストしてコンパイラを回そうとすると適切なタイプの、あなたはsegmetnationの欠陥を取得します。

class C 
{ 
public: 
    void *hello(void) 
    { 
     std::cout << "Hello, world!" << std::endl; 
     return 0; 
    } 

    static void *hello_helper(void *context) 
    { 
     return ((C *)context)->hello(); 
    } 
}; 
... 
C c; 
pthread_t t; 
pthread_create(&t, NULL, &C::hello_helper, &c); 
+0

は、次のようにベクトルで動作します: pthread_create(&t、NULL、&C :: hello_helper、&vector_c [0]); ? –

+0

すべての上記のコメントは便利です私は問題を解決するためにすべてからの組み合わせを使用..それはまだdosentは私がそれをやろうとしていたようには...しかし、unfortunatlly私は正しい、 –

+0

私はこの回答をアップヴォートしたいと思っていましたが、Cスタイルのキャストを使用しています。これは極端な偏見で終わらなければなりません。この答えは、そうでなければ正しいです。 –

5

void *型()(空)、void *型)は、」あなたはそれが探しているシグネチャと一致する機能をpthread_create与える必要があります。あなたが渡しているものはうまくいかないでしょう。

このような静的関数を実装することができ、cのインスタンスを参照して、スレッド内で実行することができます。 pthread_createは、関数ポインタだけでなく、 "コンテキスト"へのポインタを取るように設計されています。この場合は、cのインスタンスへのポインタを渡すだけです。例えば

static void* execute_print(void* ctx) { 
    c* cptr = (c*)ctx; 
    cptr->print(); 
    return NULL; 
} 


void func() { 

    ... 

    pthread_create(&t1, NULL, execute_print, &c[0]); 

    ... 
} 
+1

私はあなたが何を意味するかを見ます。c、gotcha ..のポインタを渡します。実装して試してみてください –

-1

私の推測では、これは、B/Cのは、Cでビットを台無しなっている++ B/CあなたはそれをC++のポインタではなく、Cの関数ポインタを送ることになります。明らかにdifferenceがあります。

(void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast) 

を送信してからpを送信してください。

メンバー関数でやっていることもやったことがありますが、それを使用していたクラスではという静的な関数がありました。

+0

私は上記を試しましたが、私に構文エラーを与えました。同様にそれを変更しようとしました...あなたがpthread_create(...) –

64

スレッドを処理する私の好きな方法は、それをC++オブジェクトの中にカプセル化することです。ここでは例です:

class MyThreadClass 
{ 
public: 
    MyThreadClass() {/* empty */} 
    virtual ~MyThreadClass() {/* empty */} 

    /** Returns true if the thread was successfully started, false if there was an error starting the thread */ 
    bool StartInternalThread() 
    { 
     return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0); 
    } 

    /** Will not return until the internal thread has exited. */ 
    void WaitForInternalThreadToExit() 
    { 
     (void) pthread_join(_thread, NULL); 
    } 

protected: 
    /** Implement this method in your subclass with the code you want your thread to run. */ 
    virtual void InternalThreadEntry() = 0; 

private: 
    static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;} 

    pthread_t _thread; 
}; 

それを使用するには、あなたは自分のスレッドのイベントループを含むように実装さInternalThreadEntry()メソッドでMyThreadClassのサブクラスを作成します。もちろん、スレッドオブジェクトを削除する前に、スレッドオブジェクトのWaitForInternalThreadToExit()を呼び出す必要があります(スレッドが実際に終了するかどうかを確認するメカニズムが必要です)。

+2

はい。私はまったく同じテクニックをしています。それを行うための素晴らしい方法.. – EdH

+1

これは、上記の仮想クラスの使用を理解することができる素晴らしい方法ですが、私は多くのディーパーの問題を抱えています..私はベクトルに入れられる必要がある他のスレッドを生成するスレッドを持っています。そして、すべてのスレッドに参加して参加する再帰的なループ。確かに私は適切な場所で待機を呼び出すことによってそれを行うためにも上記を実装できると確信していますが、私は –

+2

のところで 'boost :: thread'を使用してください。 – GManNickG

1

上記の答えは良いですが、私の場合は、第一のアプローチ機能を変換します。あなたは、クラスをブートストラップするために(何のthisパラメータを持っていない)静的クラスメソッド、またはプレーン通常の関数を使用する必要があります静的であることは機能しませんでした。私はスレッド関数に移行するために終了コードを変換しようとしていましたが、そのコードは静的ではないクラスのメンバーへの参照をたくさん持っていました。 C++オブジェクトへのカプセル化の2番目のソリューションは機能しますが、スレッドを実行するための3レベルのラッパーがあります。

私は、既存のC++の構造 - 「友人」機能を使用する代わりのソリューションを持っていて、私の場合には完璧に機能しました。 私は「友人」を使用する方法の例(それは友人を使用して、コンパクトな形式に変換する方法を示す名称については、上記と同じ例を使用します)

class MyThreadClass 
    { 
    public: 
     MyThreadClass() {/* empty */} 
     virtual ~MyThreadClass() {/* empty */} 

     bool Init() 
     { 
      return (pthread_create(&_thread, NULL, &ThreadEntryFunc, this) == 0); 
     } 

     /** Will not return until the internal thread has exited. */ 
     void WaitForThreadToExit() 
     { 
      (void) pthread_join(_thread, NULL); 
     } 

    private: 
     //our friend function that runs the thread task 
     friend void* ThreadEntryFunc(void *); 

     pthread_t _thread; 
    }; 

    //friend is defined outside of class and without any qualifiers 
    void* ThreadEntryFunc(void *obj_param) { 
    MyThreadClass *thr = ((MyThreadClass *)obj_param); 

    //access all the members using thr-> 

    return NULL; 
    } 

勿論、我々はブースト::スレッドを使用して回避することができますこれらはすべて、しかし、私はブーストを使用しないようにC + +コードを修正しようとしていた(コードは、この目的のためだけにブーストにリンクしていた)

1

私は誰にも役に立つだろうという希望で私の最初の答え: 今これは古い質問ですが、私はTcpServerクラスを作成していて、pthreadを使用しようとしていたので、上記の問題とまったく同じエラーが発生しました。私はこの質問を見つけ、なぜそれが起こっていたのか理解しています。 - >void* TcpServer::sockethandler(void* lp) {/*code here*/}

を、私はラムダとそれを呼び出す - 私にはクリーンなアプローチを思わ>std::thread([=] { sockethandler((void*)csock); }).detach();

スレッドを実行するための

#include <thread> 

方法:私はこれをやってしまいました。

+0

彼はstd :: threadsではなくPOSIXスレッドを要求しました – gj13

0

私はあなたがそれを求めているものを解決する方法を見つけたあまりにも多くの時間が、私の意見ではあまりにも複雑です。 例えば、新しいクラス型、リンクライブラリなどを定義する必要があります。 エンドユーザーが基本的に "thread -ize"できるようにするコードをいくつか記述しました。 ) "というものです。 具体的な方法や機能が必要な場合は、私が実装したこのソリューションを拡張、改良などできるので、 を追加してください。

ここには、私が行ったことを示す3つのファイルがあります。

// A basic mutex class, I called this file Mutex.h 
#ifndef MUTEXCONDITION_H_ 
#define MUTEXCONDITION_H_ 

#include <pthread.h> 
#include <stdio.h> 

class MutexCondition 
{ 
private: 
    bool init() { 
     //printf("MutexCondition::init called\n"); 
     pthread_mutex_init(&m_mut, NULL); 
     pthread_cond_init(&m_con, NULL); 
     return true; 
    } 

    bool destroy() { 
     pthread_mutex_destroy(&m_mut); 
     pthread_cond_destroy(&m_con); 
     return true; 
    } 

public: 
    pthread_mutex_t m_mut; 
    pthread_cond_t m_con; 

    MutexCondition() { 
     init(); 
    } 
    virtual ~MutexCondition() { 
     destroy(); 
    } 

    bool lock() { 
     pthread_mutex_lock(&m_mut); 
     return true; 
    } 

    bool unlock() { 
     pthread_mutex_unlock(&m_mut); 
     return true; 
    } 

    bool wait() { 
     lock(); 
     pthread_cond_wait(&m_con, &m_mut); 
     unlock(); 
     return true; 
    } 

    bool signal() { 
     pthread_cond_signal(&m_con); 
     return true; 
    } 
}; 
#endif 
// End of Mutex.h 

//スレッドIZE法(TEST.H)にすべての作業をincapsulatesクラス:Linux上でその

#ifndef __THREAD_HANDLER___ 
#define __THREAD_HANDLER___ 

#include <pthread.h> 
#include <vector> 
#include <iostream> 
#include "Mutex.h" 

using namespace std; 

template <class T> 
class CThreadInfo 
{ 
    public: 
    typedef void (T::*MHT_PTR) (void); 
    vector<MHT_PTR> _threaded_methods; 
    vector<bool> _status_flags; 
    T *_data; 
    MutexCondition _mutex; 
    int _idx; 
    bool _status; 

    CThreadInfo(T* p1):_data(p1), _idx(0) {} 
    void setThreadedMethods(vector<MHT_PTR> & pThreadedMethods) 
    { 
     _threaded_methods = pThreadedMethods; 
     _status_flags.resize(_threaded_methods.size(), false); 
    } 
}; 

template <class T> 
class CSThread { 
    protected: 
    typedef void (T::*MHT_PTR) (void); 
    vector<MHT_PTR> _threaded_methods; 
    vector<string> _thread_labels; 
    MHT_PTR _stop_f_pt; 
    vector<T*> _elements; 
    vector<T*> _performDelete; 
    vector<CThreadInfo<T>*> _threadlds; 
    vector<pthread_t*> _threads; 
    int _totalRunningThreads; 

    static void * gencker_(void * pArg) 
    { 
     CThreadInfo<T>* vArg = (CThreadInfo<T> *) pArg; 
     vArg->_mutex.lock(); 
     int vIndex = vArg->_idx++; 
     vArg->_mutex.unlock(); 

     vArg->_status_flags[vIndex]=true; 

     MHT_PTR mhtCalledOne = vArg->_threaded_methods[vIndex]; 
     (vArg->_data->*mhtCalledOne)(); 
     vArg->_status_flags[vIndex]=false; 
     return NULL; 
    } 

    public: 
    CSThread():_stop_f_pt(NULL), _totalRunningThreads(0) {} 
    ~CSThread() 
    { 
     for (int i=_threads.size() -1; i >= 0; --i) 
      pthread_detach(*_threads[i]); 

     for (int i=_threadlds.size() -1; i >= 0; --i) 
     delete _threadlds[i]; 

     for (int i=_elements.size() -1; i >= 0; --i) 
     if (find (_performDelete.begin(), _performDelete.end(), _elements[i]) != _performDelete.end()) 
       delete _elements[i]; 
    } 
    int runningThreadsCount(void) {return _totalRunningThreads;} 
    int elementsCount()  {return _elements.size();} 
    void addThread (MHT_PTR p, string pLabel="") { _threaded_methods.push_back(p); _thread_labels.push_back(pLabel);} 
    void clearThreadedMethods() { _threaded_methods.clear(); } 
    void getThreadedMethodsCount() { return _threaded_methods.size(); } 
    void addStopMethod(MHT_PTR p) { _stop_f_pt = p; } 
    string getStatusStr(unsigned int _elementIndex, unsigned int pMethodIndex) 
    { 
     char ch[99]; 

     if (getStatus(_elementIndex, pMethodIndex) == true) 
     sprintf (ch, "[%s] - TRUE\n", _thread_labels[pMethodIndex].c_str()); 
     else 
     sprintf (ch, "[%s] - FALSE\n", _thread_labels[pMethodIndex].c_str()); 

     return ch; 
    } 
    bool getStatus(unsigned int _elementIndex, unsigned int pMethodIndex) 
    { 
     if (_elementIndex > _elements.size()) return false; 
     return _threadlds[_elementIndex]->_status_flags[pMethodIndex]; 
    } 

    bool run(unsigned int pIdx) 
    { 
     T * myElem = _elements[pIdx]; 
     _threadlds.push_back(new CThreadInfo<T>(myElem)); 
     _threadlds[_threadlds.size()-1]->setThreadedMethods(_threaded_methods); 

     int vStart = _threads.size(); 
     for (int hhh=0; hhh<_threaded_methods.size(); ++hhh) 
      _threads.push_back(new pthread_t); 

     for (int currentCount =0; currentCount < _threaded_methods.size(); ++vStart, ++currentCount) 
     { 
       if (pthread_create(_threads[vStart], NULL, gencker_, (void*) _threadlds[_threadlds.size()-1]) != 0) 
     { 
       // cout <<"\t\tThread " << currentCount << " creation FAILED for element: " << pIdx << endl; 
        return false; 
       } 
     else 
     { 
      ++_totalRunningThreads; 
      // cout <<"\t\tThread " << currentCount << " creation SUCCEDED for element: " << pIdx << endl; 
       } 
     } 
     return true; 
    } 

    bool run() 
    { 
      for (int vI = 0; vI < _elements.size(); ++vI) 
      if (run(vI) == false) return false; 
      // cout <<"Number of currently running threads: " << _totalRunningThreads << endl; 
     return true; 
    } 

    T * addElement(void) 
    { 
     int vId=-1; 
     return addElement(vId); 
    } 

    T * addElement(int & pIdx) 
    { 
     T * myElem = new T(); 
     _elements.push_back(myElem); 
     pIdx = _elements.size()-1; 
     _performDelete.push_back(myElem); 
     return _elements[pIdx]; 
    } 

    T * addElement(T *pElem) 
    { 
     int vId=-1; 
     return addElement(pElem, vId); 
    } 

    T * addElement(T *pElem, int & pIdx) 
    { 
     _elements.push_back(pElem); 
     pIdx = _elements.size()-1; 
     return pElem; 
    } 

    T * getElement(int pId) { return _elements[pId]; } 

    void stopThread(int i) 
    { 
     if (_stop_f_pt != NULL) 
     { 
     (_elements[i]->*_stop_f_pt)() ; 
     } 
     pthread_detach(*_threads[i]); 
     --_totalRunningThreads; 
    } 

    void stopAll() 
    { 
     if (_stop_f_pt != NULL) 
     for (int i=0; i<_elements.size(); ++i) 
     { 
      (_elements[i]->*_stop_f_pt)() ; 
     } 
     _totalRunningThreads=0; 
    } 
}; 
#endif 
// end of test.h 

//使用例ファイル "test.cc" I メソッドをスレッド化するすべての作業をカプセル化していないクラス: g ++ -o mytest.exe test.cc -I。 -lpthread -lstdC++

#include <test.h> 
#include <vector> 
#include <iostream> 
#include <Mutex.h> 

using namespace std; 

// Just a class for which I need to "thread-ize" a some methods 
// Given that with OOP the objecs include both "functions" (methods) 
// and data (attributes), then there is no need to use function arguments, 
// just a "void xxx (void)" method. 
// 
class TPuck 
{ 
    public: 
    bool _go; 
    TPuck(int pVal):_go(true) 
    { 
    Value = pVal; 
    } 
    TPuck():_go(true) 
    { 
    } 
    int Value; 
    int vc; 

    void setValue(int p){Value = p; } 

    void super() 
    { 
    while (_go) 
    { 
     cout <<"super " << vc << endl; 
      sleep(2); 
     } 
     cout <<"end of super " << vc << endl; 
    } 

    void vusss() 
    { 
    while (_go) 
    { 
     cout <<"vusss " << vc << endl; 
     sleep(2); 
    } 
     cout <<"end of vusss " << vc << endl; 
    } 

    void fazz() 
    { 
    static int vcount =0; 
    vc = vcount++; 
    cout <<"Puck create instance: " << vc << endl; 
    while (_go) 
    { 
     cout <<"fazz " << vc << endl; 
     sleep(2); 
    } 
    cout <<"Completed TPuck..fazz instance "<< vc << endl; 
    } 

    void stop() 
    { 
     _go=false; 
     cout << endl << "Stopping TPuck...." << vc << endl; 
    } 
}; 


int main(int argc, char* argv[]) 
{ 
    // just a number of instances of the class I need to make threads 
    int vN = 3; 

    // This object will be your threads maker. 
    // Just declare an instance for each class 
    // you need to create method threads 
    // 
    CSThread<TPuck> PuckThreadMaker; 
    // 
    // Hera I'm telling which methods should be threaded 
    PuckThreadMaker.addThread(&TPuck::fazz, "fazz1"); 
    PuckThreadMaker.addThread(&TPuck::fazz, "fazz2"); 
    PuckThreadMaker.addThread(&TPuck::fazz, "fazz3"); 
    PuckThreadMaker.addThread(&TPuck::vusss, "vusss"); 
    PuckThreadMaker.addThread(&TPuck::super, "super"); 

    PuckThreadMaker.addStopMethod(&TPuck::stop); 

    for (int ii=0; ii<vN; ++ii) 
    { 
    // Creating instances of the class that I need to run threads. 
    // If you already have your instances, then just pass them as a 
    // parameter such "mythreadmaker.addElement(&myinstance);" 
    TPuck * vOne = PuckThreadMaker.addElement(); 
    } 

    if (PuckThreadMaker.run() == true) 
    { 
    cout <<"All running!" << endl; 
    } 
    else 
    { 
    cout <<"Error: not all threads running!" << endl; 
    } 

    sleep(1); 
    cout <<"Totale threads creati: " << PuckThreadMaker.runningThreadsCount() << endl; 
    for (unsigned int ii=0; ii<vN; ++ii) 
    { 
    unsigned int kk=0; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    } 

    sleep(2); 
    PuckThreadMaker.stopAll(); 
    cout <<"\n\nAfter the stop!!!!" << endl; 
    sleep(2); 

    for (int ii=0; ii<vN; ++ii) 
    { 
    int kk=0; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
    } 

    sleep(5); 
    return 0; 
} 

// End of test.cc