5

valgrind(helgrind) ツールを学び始めたとき、私が取り組むことができなかったような厄介な問題に遭遇しました。

簡単に言えば、ユーザー定義のスレッドクラスは、スレッドのエントリルーチンによって呼び出される仮想関数で作成されます。この場合、helgrind は、Possible-data-race を報告します。しかし、単純に virtual キーワードを省略した後では、そのようなエラーは報告されません。どうしてこうなるのか。私のコードに何か問題がありますか? または回避策はありますか?

以下は、cpp、Makefile、および helgrind が報告するメッセージを含む、このような問題を示す単純なスレッド化されたアプリケーションです。

/* main.cpp */
#include <memory.h>
#include <pthread.h>

class thread_s {
public:
  pthread_t       th;
  thread_s(void);
  ~thread_s(void);
  virtual void* routine(); /* if omit virtual, no error would be generated */
  void stop(void);
};
static void* routine(void*);
int main(int, const char*[])
{
  thread_s s_v;
  pthread_create(&s_v.th, 0, routine, &s_v);
  return 0;
}
static void* routine(void* arg)
{
  thread_s *pV = reinterpret_cast<thread_s*>(arg);
  pV->routine();
  return 0;
}
void* thread_s::routine(void)
{
  return 0;
}
thread_s::thread_s(void)
{
  th = 0;
}
thread_s::~thread_s(void)
{
  stop();
}
void thread_s::stop(void)
{
  void *v = 0;
  pthread_join(th, &v);
}

=======================================

/* Makefile */
all: main test_helgrind

main: main.cpp
        g++ -o main main.cpp \
        -g -Wall -O0 \
        -lpthread

test_helgrind:
        valgrind \
                --tool=helgrind \
                ./main

clean:
        rm -f main

.PHONY: clean

=======================================

g++ -o main main.cpp \
        -g -Wall -O0 \
        -lpthread
valgrind \
                --tool=helgrind \
                ./main
==7477== Helgrind, a thread error detector
==7477== Copyright (C) 2007-2010, and GNU GPL'd, by OpenWorks LLP et al.
==7477== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==7477== Command: ./main
==7477==
==7477== Thread #1 is the program's root thread
==7477==
==7477== Thread #2 was created
==7477==    at 0x4259728: clone (clone.S:111)
==7477==    by 0x40484B5: pthread_create@@GLIBC_2.1 (createthread.c:256)
==7477==    by 0x4026E2D: pthread_create_WRK (hg_intercepts.c:257)
==7477==    by 0x4026F8B: pthread_create@* (hg_intercepts.c:288)
==7477==    by 0x8048560: main (main.cpp:18)
==7477==
==7477== Possible data race during write of size 4 at 0xbeab24c8 by thread #1
==7477==    at 0x80485C9: thread_s::~thread_s() (main.cpp:35)
==7477==    by 0x8048571: main (main.cpp:17)
==7477==  This conflicts with a previous read of size 4 by thread #2
==7477==    at 0x804858B: routine(void*) (main.cpp:24)
==7477==    by 0x4026F60: mythread_wrapper (hg_intercepts.c:221)
==7477==    by 0x4047E98: start_thread (pthread_create.c:304)
==7477==    by 0x425973D: clone (clone.S:130)
==7477==
==7477==
==7477== For counts of detected and suppressed errors, rerun with: -v
==7477== Use --history-level=approx or =none to gain increased speed, at
==7477== the cost of reduced accuracy of conflicting-access information
==7477== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)
4

2 に答える 2

3

これが helgrind の苦情の理由かどうかはわかりませんが、あなたのプログラムには深刻な問題があります。thread_sスレッドを作成し、ローカルインスタンスへのポインターを渡します ( s_vin main())。

ただし、main()スレッドとの同期を行わずにすぐに戻ります。s_vスレッド関数routine()がポインターを取得し、それを使用してpV->routine().

呼び出しの後に次を追加するpthread_create()と、helgrind が文句を言うのを防ぐことができるかどうかを確認します。

pthread_join( s_v.th, NULL);

実際、helgrind の出力を詳しく見てみると、ログはthread_sデータ競合の 1 つの参加者としてデストラクタを指しているため、ほぼ確実に helgrind の苦情が取り除かれます。

于 2012-08-31T09:34:57.713 に答える
2

ある場合にはvptrが書き込まれ、他の場合には読み取られます。ロックが保持されていない両方。Helgrindは、この状態が2つのスレッドで同時に発生することを不可能にする他の手段がプログラムにあるかどうかを知ることができないため、フラグを立てます。別のスレッドで誰かがオブジェクトの関数を呼び出そうとしているときにオブジェクトが破棄されないことを保証できる場合は、これに対する抑制を生成できます。

于 2012-08-31T09:33:53.567 に答える