3

私は仕事に行くのに苦労してboost:threadいます。最適化なしでコンパイルすると問題なく動作します。

g++ -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread

しかし、最適化でコンパイルされたバージョンはクラッシュします

g++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread
Segmentation fault

何が原因か誰か知っていますか?

私が使用しているコードは次のとおりです。

#include <boost/thread.hpp>
#include <boost/function.hpp>

void task1() {
  // do something
}
void task2() {
  // do something
}

int main (int argc, char ** argv) {
  using namespace boost;

  function0<void> f1(&task1);
  function0<void> f2(&task2);

  thread thread_1(f1);
  thread thread_2(f2);

  // do other stuff 
  thread_2.join();
  thread_1.join();
  return 0;
}

PS: ubuntu Linux でブースト 1.32 を使用しています。

アップデート:

デバッガーでクラッシュする場所は次のとおりです (37 行目はthread_2.join();元のコードの 1 つです)。

(gdb) bt
#0  0x080499e0 in boost::thread::join ()
#1  0x080496b8 in main (argc=1, argv=0xbfea3eb4) at ../src/test-thread.cpp:37

ここに私の実際の2つの機能があります:

void task1() {
  std::cerr << "THREAD 1 START" << std::endl;
  for(double i=0; i<999999; ++i){
    std::cout << i << std::endl;
  }
  std::cerr << "THREAD 1 END" << std::endl;
}

void task2() {
  std::cerr << "THREAD 2 START" << std::endl;
  for(double i=0; i<999999; ++i){
    std::cout << i << std::endl;
  }
  std::cerr << "THREAD 2 END" << std::endl;
}

助けてくれてありがとう!

4

2 に答える 2

3

バグを見つけました!間違ったバージョンのライブラリに対してリンクしていました。私はを使用していましたが、代わりboost_thread-gcc-mt-sに動作しboost_thread-gcc-mtます:

g++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt -lpthread

Boostのドキュメントを調べましたが、これらのライブラリバージョンの違いについての情報は見つかりませんでした。デバッグバージョンであると私が想定しているもありますがboost_thread-gcc-mt-d、それに対してリンクすると、でコンパイルした場合でも、常にセグメンテーション違反のバイナリが発生し-gます。しかし、少なくとも今はスレッドを実行できます。

于 2009-02-21T21:17:43.643 に答える
3

コア ダンプがアクティブであることを確認し ( ulimit -c unlimited)、シンボルを使用してコンパイルし (-O2 -g)、実行して、gdb でスタック トレースを開きますか? ( gdb test-thread core、プロンプトで入力backtraceして終了します)gdbquit

アップデート

バックトレースに基づいて、セグメンテーション違反が で発生し boost::thread::joinます。コアを再度開いてください。

  • boost::thread::joinメソッド の逆アセンブリを取得します。
    • disassemble boost::thread::join
    • disassemble
  • レジスターのダンプを取得します。
    • info registers

(boost 1.32の公式ソース) の実装 boost::thread::joinは非常に単純なので、Ubuntu バイナリが公式コード (逆アセンブルから明らかになることを願っています) から大幅に逸脱していない限り、セグメンテーション違反の原因は 2 つしか考えられません。

また、セグメンテーション違反が発生する前に 2 つのスレッドがどの程度印刷されたか確認できますか?

void thread::join()
{
    int res = 0;
#if defined(BOOST_HAS_WINTHREADS)
    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
    assert(res == WAIT_OBJECT_0);
    res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
    assert(res);
#elif defined(BOOST_HAS_PTHREADS)
    res = pthread_join(m_thread, 0);
    assert(res == 0);
#elif defined(BOOST_HAS_MPTASKS)
    OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(
        m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
    assert(lStatus == noErr);
#endif
    // This isn't a race condition since any race that could occur would
    // have us in undefined behavior territory any way.
    m_joinable = false;
}

この種の問題の通常の原因:

  • 初期化されていない変数
  • マークされていない両方のスレッドによってアクセスされる変数volatile
  • インライン呼び出しおよび/または展開されたループ (スタック フレーム サイズはすべてのインライン メソッド インスタンスのスタック フレームの合計です) が再帰的に呼び出され、非インライン バージョンよりもはるかに高速にスタックをオーバーフローさせます。
于 2009-02-21T01:47:44.983 に答える