2017-06-30 7 views
0

pthreadを使用してスレッドクラスを実装したいと思います。 もちろん、作成しているスレッドごとに異なる起動ルーチンを用意したいと思います。 pthread_create thoはスタティック関数のみを開始ルーチンとして許可するため、インスタンス化できません。 これを可能にする方法はありますか、スレッドを処理するために構造体を使用する方が良いですか? これは私がSOFAR書いたコードは次のとおりです。Posixスレッドクラスとスタートルーチン(pthread)

class thread { 

    string name; 
    pthread_t id; 
    pthread_mutex_t mutex; 
    pthread_cond_t cond; 
    pthread_attr_t attr; 

public: 
    thread (string t_name); 

static void* start(void*); 

int id_get(); 


private: 

}; 

thread::thread (string t_name) 
{ 

    name = t_name; 
    pthread_attr_init(&attr); 
    int stacksize = sizeof(double) * TH_STACK_SIZE * 30; 
    pthread_attr_setstacksize(&attr, stacksize); 
    int rc = pthread_create (&id, &attr, &start, NULL); 

    cout << "return_code: " << rc << endl; 
    cout << id; 


} 
void* thread::start(void*) 
    { 
while(1){ 
cout << "here"; 
pthread_exit(NULL); 
    } 
    } 

int thread::id_get() 
{ 
    return id; 

} 

と主な私のテスト:あなたはのavailble POSIXスレッドを使用している場合

int main(void) { 
    cout << "Creating threads" << endl; 
    thread test1("first"); 
    thread test2("second"); 

    pthread_join(test1.id_get(),NULL); 
    pthread_join(test2.id_get(),NULL); 

    return 0; 

} 
+3

既存のstd :: threadを使用しないのはなぜですか? –

+0

原因私はARM用にクロスコンパイルしているので、pthreadははるかに移植性があります(少なくとも私が読んだことです)。 – Podarce

+0

stdは何を表していますか? –

答えて

1

私は を作成しているスレッドごとに異なる開始ルーチンを使用したいと思います。

戻る私は、POSIXスレッドを使用する場合(私は今のstd ::スレッドを使用するには)、私は「二段階」エントリのメカニズムを使用していました。これらの2つのステップの(わずかな)コストで、すべてのクラスは簡単に独自のスレッドを持つことができます。

私はこれらのエントリメソッドを常に非公開にしています。

class Foo_t 
{ 

    // ... etc 

private: 
    static void* threadEntry(void* ptr); 

    void* threadEntry2(void); // thread actions in an object method 

    // ... etc 
} 

これらはプライベートなので、クラスのようなもの、通常、POSIXスレッドを作成するためのいくつかのパブリックメソッドがあります。)

void Foo_t::startApp() 
{ 
    // ... etc 

    int pcStat = m_Thread.create(Foo_t::threadEntry, this); 
    // this 2 parameter method of my thread wrapper class 
    // invoked the 4 parameter "::pthread_create(...)". 
    // The 'this' param is passed into the 4th parameter, called arg. 
    dtbAssert(0 == pcStat)(m_nodeId)(pcStat)(errno); 

    // ... 
} 

注意m_Thread.create(2番目のパラメータ、「これ」を、 。

スレッドは静的メソッドで開始する

void* Foo_t::threadEntry(void* a_ptr) 
{ 
    dtbAssert(a_ptr != 0); 

    Foo_t* a_foo = static_cast<Foo_t*>(a_ptr); 

    void* retVal = a_foo->threadEntry2(); 

    return(retVal); 

}

ここで、パラメータは、クラスインスタンスの「この」ポインタで充填されている*ボイド、およびstatic_castをバックに私たちが必要とするのは、Foo_t *です。このメソッドはプライベートなので、startApp()だけがスレッドを作成することに注意してください。threadEntryは()と呼ばれるクラスのインスタンスの実際のメソッドを呼び出す

注:

void* Foo_t::threadEntry2(void) 
{ 
    DBG("Thread %2d (id=%lx): sems %p/%p, " 
     "Entering sem controlled critical region\n", ...); 

    // ... start thread work 

} 

そして、ここから、インスタンスの任意の方法が利用可能です。


異なるスレッドルーチンに進むには非常に多くの方法があります。

はにstartAppにパラメータを追加することを検討:

void Foo_t::startApp(int select); 

) 'を選択int型' とスイッチ/ case文は(ユニークthreadEntryを実行することができます。

threadEntry()の後のスイッチ/ケースが一意のメソッドまたはthreadEntry2_x()を実行できるように、おそらく 'int select'を(インスタンスで)インストールすることができます。

または、スイッチ/ケースがthreadEntry2()にインストールされている可能性があります。

startAppパラメータがメソッドポインタである可能性があることを考慮してください。

void Foo_t::startApp(<method pointer>); 

メソッドのポインタは、固定された名前threadEntry2()の代わりに(幾分直接的に)呼び出すことができます。

上記は小さな問題です。

インスタンスで1つ以上のスレッドが実行されているミューテックスは、より大きな問題です。

私は実際には、単一のクラスインスタンス内に複数のスレッドが走り回っています。そのために、ミューテックスやその他のガードメカニズムの下でクリティカルセクションを使用しました。 std :: mutexは便利で、 'Posix'スレッドで動作しますが、Ubuntuでは、ローカルモード(無名、非共有)に設定されたPosixプロセスセマフォを使用することがよくあります。 PPLSem_tは効率的で、小さなクラスでラップされた4つの1行のメソッドに適合します。


pthread_createのカントーは それをインスタンス化することができない、ルーチンを開始するようにのみ静的機能を可能にします。

静的メソッドを含むクラスのインスタンスをインスタンス化することは難しいことではありません。このステートメント/文脈であなたが何を意味するのか分かりません。

上記のアプローチを見直すと、すぐにクラスインスタンスのPosixスレッドが機能するはずです。


ARMシステムで使用できるスタックの量とRAMの量を確認してください。 Ubuntuのデフォルトのスタックサイズは8 MBです。おそらくあなたのARMはスタックサイズのコントロールを提供します。

+0

スタックサイズ "int stat = pthread_attr_getstacksize(&tattr、&size);")が実行されているスレッドのPosixルーチンがあります。 –

+0

スレッドがスレッドインスタンスを作成しようとしている可能性がありますpthread_create()_can_関数を呼び出す(つまりメソッドではない)、この関数はあるクラスの静的メソッドである必要はありません。関数を実行するスレッドはクラスインスタンスをインスタンス化し、publicを介してインスタンスにジャンプできますしかし、私は、プライベートスレッドを起動するインスタンスを好む。 –

1

は、std::threadは、現在の標準をサポートする任意のC++コンパイラのために利用できるようになります(C以来++ 11)。

基本的に、クロスコンパイルされたターゲットに対して独自のthreadクラスをロールする必要はありません(GCCはバージョン4.9以降でサポートしています)。


しかし、一般的にはあなたのアプローチは正しいです。様々なクラスのためにそれを適用できるようにするには、simmply threadクラステンプレート加えることができます。

template<typename T> 
class thread { 

    string name; 
    pthread_t id; 
    pthread_mutex_t mutex; 
    pthread_cond_t cond; 
    pthread_attr_t attr; 

public: 
    thread (string t_name, T& runnable); 

    static void* start(void*); 

    int id_get(); 
    T& runnable_; 
}; 

を、次のようにコンストラクタとstart()機能を実装します。

template<typename T> 
thread<T>::thread (string t_name) 
: name(t_name) 
, runnable_(runnable) 
{  
    pthread_attr_init(&attr); 
    int stacksize = sizeof(double) * TH_STACK_SIZE * 30; 
    pthread_attr_setstacksize(&attr, stacksize); 
    int rc = pthread_create (&id, &attr, &start, this); 
              // ^^^^ 

    cout << "return_code: " << rc << endl; 
    cout << id; 
} 

template<typename T> 
void* thread<T>::start(void* pThis) { 
    thread<T>* realThis = reinterpret_cast<thread<T>*>(pThis); 
    (realThis->runnable)_.start(); 
    pthread_exit(NULL); 
} 

次のようthreadクラスは、次に使用することができます:

struct MyRunnable { 
    MyRunnable(/* Whatever parameters needed */) 
    : /* Whatever needs to be initialized */ { 
    } 
    void start() { 
     /* Full access to all class member variables */ 
    } 
} 

int main() { 
    MyRunnable run(/* Whatever parameters needed */); 
    thread<MyRunnable> t("TheTreadName",run); // start() will execute here 
    // do concurrent stuff 
    t.join(); 
} 

私はただのCLAを避けるためにthreadとして別の名前を選ぶだろうC++の標準ライブラリを使用しています。