2012-01-20 13 views
2

Boost :: threadsを使用してスレッドクラスで奇妙な問題が発生しています。ここでは、私がやっていることの簡単な要約です:組み込みARMでセグメンテーションフォールトにつながるBoost :: Thread関数

ルーチンは、継承ツリーを形成する基本クラスへの共有ポインタであるプライベートデータメンバを持つハンドラクラスで構成されるオブジェクトの束を作成します。私はこのルーチンが問題なく動作していると確信しています。

次に、スレッドクラスの新しいインスタンスを作成するハンドラクラス(startUpdate)のメソッドを呼び出します。ここでスレッドクラスコードは次のとおりです。

class Sensor_Thread 
{ 
    public: 
    //constructor (creates thread and binds the update function to it 
    Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false), 
         s (theSensor), 
         m_thread (boost::bind (&Sensor_Thread::update, this)) { } 
    //default null constructor, shouldn't ever be used 
    Sensor_Thread(): m_stoprequested (true), 
         m_thread(), 
         s (NULL) { } 

    //destructor (automatically joins the thread as per RAII principles) 
    ~Sensor_Thread() { m_stoprequested = true; m_thread.join(); } 

    private: 
    volatile bool m_stoprequested; 
    boost::mutex m_mutex; 
    boost::thread m_thread; 
    Ptr<Sensor_Base> s; 

    void update(); 

}; 

(「Ptrは」クラスがあり、私の共有ポインタクラス...私は...私はもともとC++教科書からそれを得たので、それが正しく動作するかなり確信しています)

更新機能:

void Sensor_Thread::update() 
{ 
    //make sure we actually have a sensor attached... 
    if (s) { 
    // set up structure for sleeping 
    struct timespec time; 
    while (!m_stoprequested) 
    { 
     boost::mutex::scoped_lock lock(m_mutex); 
     s->update(); 
     time.tv_sec = s->updateInterval/1000; 
     time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000); 
     nanosleep (&time, NULL); 
    } 
    } 
} 

ドライバ内の別のトリガstopUpdateを呼び出し、threaded_classが破壊されるまで無期限に実行されます。

奇妙なこと: 私の開発ボックスでは、OS X 10.6で、darwin gcc 4.2.1を使用していますが、期待どおり正確に動作します。

これは、debian linuxとARMプロセッサを搭載した組み込みサーバ上で実行するためのものです。私は組み込みシステムの製造元が提供するクロスコンパイルツールチェインを持っており、これをクロスコンパイルに使用するとseg faultが発生します。デバッグを通して、私はこのsegフォールトがs-> update()が呼び出されたとき(または共有ポインタを参照解除して何かをしようとする他の試み)に発生することを発見しました。しかし、少し遅れて、「sleep(1);」を追加すると、私のSensor_Thread :: update関数でwhileループを開始する前に、完璧に動作します。

これは、システムが完全にまたは適切に初期化される前に、共有ポインタを逆参照しようとしていることを暗示しているようです。睡眠(1)の回避策は機能しますが、それでも私にとっては非常に奇妙です。スレッド化されたクラスの共有ポインタがコンストラクタの間に初期化されていれば、更新関数が呼び出される前に準備ができていないはずです。または、boost :: threadの作成は、更新関数がスレッドクラスが所有する共有ポインタの初期化と同時に発生することを意味しますか?更新関数が呼び出される前に共有ポインタが初期化されていることを確認するために "スリープ"ハックよりもクリーンな方法はありますか?

ありがとうございました!

+0

あなたの教科書に対する信仰はチャーミングです。 :) – sarnold

答えて

3
Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false), 
        s (theSensor), 
        m_thread (boost::bind (&Sensor_Thread::update, this)) { } 

このコードは壊れています。まだ構築されていないオブジェクトに対してupdateを呼び出しています。コンストラクタの初期化リストにthisを使用すると、常に赤いフラグが立てられます。まだ完全には存在しないオブジェクトへのポインタです。

これを処理する通常の方法は、2つのステップに分割することです。スレッドを作成する方法はrunまたはstartです。コンストラクタが返った後、そのメソッドを呼び出します。

while (!m_stoprequested) 
{ 
    boost::mutex::scoped_lock lock(m_mutex); 
    s->update(); 
    time.tv_sec = s->updateInterval/1000; 
    time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000); 
    nanosleep (&time, NULL); 
} 

これはおそらくあなたが望むものではありません。 mutexを保持していますは常にです。別のスレッドがsにアクセスすることは非常に困難です。次回の更新まで待たなければならず、ミューテックスのレースに勝つ必要があります。いくつかのプラットフォームでは、実際の作業を行っているスレッドは、(インタラクティブな)スレッド(ほとんどがスリープしているスレッド)を叩くのに苦労するでしょう。これにより、sにかなりの量だけアクセスしようとする他のスレッドが遅くなる可能性があります。

なぜmutexを持っている間にnanosleepに電話をしますか?

+0

ありがとう!スターターメソッドを追加するのに十分なはずです。多分あなたが言うことができるように、私はマルチスレッドプログラミングの初心者です。私はこれをオンラインで見つけた例をベースにしています... 私は多分ミューテックスについて少し混乱しています。私の目標は、s-> update()メソッドの実行中に他のオブジェクトがオブジェクトへのアクセス権を持つことを許可しないことです(sは共有ポインタです)。 nanosleep関数は更新間隔を設定するだけであり、間違いなくmutex内部にある必要はありません。どのようにして目標を達成するのかについての洞察はありますか? – bencpeters

+0

scoped_lockを削除し、mutexを 'update'の前にロックしてからロックを解除することができます。代わりに、scoped_lockと 'update'呼び出しを' if 1'ブロックの中に置くこともできます。 (もし他のスレッドが* '*' s'を変更するならば、2つの計算をロックの中に入れてください。そうでなければ、どちらの方法でも問題はありませんが、できるだけ少ない命令でmutexを保持するのが一般的です。 –

関連する問題