質問

QNXで実行したいこのコードに関する質問があります:

class ConcreteThread : public Thread
{
public:
    ConcreteThread(int test)
    {
        testNumber = test;
    }

    void *start_routine() 
    { 
        for(int i = 0; i < 10; i++)
        {
            sleep(1);
            cout << testNumber << endl;
        }   
    }

private:
    int testNumber;
};




class Thread 
{
public:
    Thread(){};

    int Create()
    {
        pthread_t m_id;
        return pthread_create(&m_id, NULL, &(this->start_routine_trampoline), this);
    }

protected:
    virtual void *start_routine() = 0;

private:

    static void *start_routine_trampoline(void *p)
    {
        Thread *pThis = (Thread *)p;
        return pThis->start_routine();
    }
};

今、* start_routineでスリープせずにこのコードを実行すると、次のコード行(並列ではなく順次)に進む前に、数値を10回出力するだけです。ただし、コードのようにスリープを使用すると、数字はまったく出力されず、コードの次の行に進みます。スリープしないのはなぜですか?順次実行するのではなく、このようなスレッドを作成するにはどうすればよいですか?

役に立ちましたか?

解決

注1:プロセッサが1つしかない場合、作成するスレッドの数に関係なく、コードは連続してしか実行できません。各スレッドには、次のスレッドのためにスワップアウトされる前にプロセッサー時間がスライスされます。

注2:メインスレッドが終了した場合、pthreadは実行する前にすべての子スレッドを強制終了します。

質問に答える:

睡眠なし。一度開始されたスレッドは、ループを完全に10回実行するために与えられた単一スライスで十分な時間を持っています。

スリープ状態:ワーカースレッドは1秒間スリープ状態になります。したがって、メインスレッドには多くの作業を行う時間があります。この時間内にメインスレッドが終了すると、ワーカーは強制終了されます。

次の変更を行います。

//  Remove the Create() method
//  Put thread creation in the constructor.
//  Make the thread variable part of the object

pthread_t m_id;

Thread()
{
    if (pthread_create(&m_id, NULL, &(this->start_routine_trampoline), this) != 0)
    {
        throw std::runtime_error("Thread was not created");
    }
}

// Make sure the destructor waits for the thread to exit.
~Thread()
{
    pthread_join(m_id);
}

ブーストスレッドライブラリをご覧ください。このような小さな間違いはすべてすでに処理されていることがわかります。したがって、スレッド化を使いやすくします。

また注意してください。静的を使用することは可能ですが、移植性はありません。これは、pthreadがCライブラリであり、C ABIを使用した関数ポインターを期待しているためです。ここであなたのプラットフォームが幸運になっています。これを関数として定義し、extern&quot; C&quot;

を使用してABIを宣言する必要があります
// This needs to be a standard function with C Interface.
extern "C" void *start_routine_trampoline(void *p)
{
}

他のヒント

pthread_t idを、関数のローカル変数ではなくクラスメンバーにしてみてください。そうすれば、呼び出し元はpthread_joinできます。

これを行わないと、技術的にはリソースリークになります(スレッドが明確に参加できない場合を除く)。参加することで、 Martin York が説明した問題を回避できます。

man pthread_joinから:

  

結合されたスレッドthは、結合可能な状態である必要があります。   pthread_detach(3)またはPTHREAD_CREATE_DETACHEDを使用して切り離された   pthread_create(3)の属性。

     

結合可能なスレッドが終了すると、そのメモリリソース(スレッド   記述子とスタック)は、別のスレッドが実行するまで割り当て解除されません   その上でpthread_join。したがって、pthread_joinは   メモリリークを回避するために作成された各結合可能スレッド。

ここで接線に出ます... Martin Yorkの投稿に関して:

  

また注意してください。静的を使用することは可能ですが、移植性はありません。これは、pthreadがCライブラリであり、C ABIを使用した関数ポインターを期待しているためです。ここであなたのプラットフォームが幸運になっています。これを関数として定義し、extern&quot; C&quot; を使用してABIを宣言する必要があります

//これはCの標準関数である必要がありますインタフェース。
extern&quot; C&quot; void * start_routine_trampoline(void * p){...}

それについてはよくわかりません...

(1)C ++は、できるだけCと互換性があるように設計されました。 いくつかの違いがあります... しかし、 extern&quot; C&quot; は、C ++関数のオーバーロードを実装するために必要な名前の変換を回避するために主に使用されました。

(2)関数ポインタを取得したら、呼び出し規約(関数呼び出しを行うためにスタックにプッシュされるもの)は、Cとamp;で同じでなければならないようです。 C ++。それ以外の場合、関数ポインターはどのように機能しますか?

例:

Cコード:

void bar( int i ) { printf( "bar %d\n", i ); }

C ++コード:

class Foo
{
public:
  static void foo( int i ) { cout << "foo " << i << endl; }
};

extern "C" { void bar(int); }

int main()
{
  void (*p)(int);

  p = & Foo::foo;
  (*p)(1);

  p = & bar;
  (*p)(2);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top