1

アップデート3

最近、私のコードがランダムにセグメンテーション違反エラーを引き起こすことに気づきました。しかし、私のコードはこれまでのところ非常に単純であり、そのエラーがどこから来ているのか理解できません。ランダムに発生するため、何らかの競合状態があると思います。これが関連する可能性のあるすべてのコードだと思います。さらに必要な場合は教えてください。

namespace thread {
    pthread_t terminated_thread_id, /* and others */;
    pthread_mutex_t terminate_thread = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t terminate_thread_signal = PTHREAD_COND_INITIALIZER;
    int total_thread_count = 0;
    int termination; // + sembufs

    inline void* Exit(void* value) {
    //  This must be unlocked after all join-related jobs are done
        semop(thread::termination, thread::termination_in_process, 2)
            pthread_mutex_lock(&thread::terminate_thread);
                thread::terminated_thread_id = pthread_self();
                pthread_cond_signal(&thread::terminate_thread_signal);
            pthread_mutex_unlock(&thread::terminate_thread);

        pthread_exit(value);
        return value;
    }
}
int main(int argc, const char** argv){
...
    pthread_mutex_lock(&thread::terminate_thread);
    if(0 != pthread_create(&thread::communication_handler_thread_id, NULL,    \
                           CommunicationHandler, NULL)){
        global::PrintDebug("pthread_create() failed", __FILE__, __LINE__);
    }
    /** 2 more pthread_create()-calls */       
    do{
        thread::terminated_thread_id = pthread_self();
        pthread_cond_wait(&thread::terminate_thread_signal,                   \
                          &thread::terminate_thread);
        if(!pthread_equal(thread::terminated_thread_id, pthread_self())){
            pthread_join(thread::terminated_thread_id, NULL);
    ...
            semop(thread::termination, thread::termination_done, 1)
        }
    }while(thread::total_thread_count > 0);

    pthread_mutex_unlock(&thread::terminate_thread);
    return 0;
}

シグナルterminate_thread_signalは、thread :: Exit()関数でのみ発行されます。この関数は、スレッドの作成に使用される関数の最後でのみ呼び出されます。

これは、デバッガーがコールスタックに対して表示するものです。

#0 (    0xb7fe2424 in __kernel_vsyscall() (??:??)
#1 0xb7fbdfcf   __pthread_cond_wait(cond=0x80539c0, mutex=0x8053998) (pthread_cond_wait.c:153)
#2 0x804a094    main(argc=1, argv=0xbffff9c4) (/home/papergay/SeekYourCar/0.2/Server/main.cpp:121)

私がすでに知っているのは、エラーが発生した場合、thread :: Exit()を呼び出したスレッドはまだないということです。また、いくつかの初期化を伴う名前のない名前空間を使用しています(それが関連している可能性がある場合)。IDEとしてCode::Blocksを使用し、コンパイラーとしてGCCを使用しています。

4

3 に答える 3

1

pthread_cond_wait()は誤ってウェイクアップすることが許可されているため、ウェイクアップするたびに状態自体を再テストする必要があります。これが問題の原因である可能性があります。メインスレッドthread::terminated_thread_idが設定される前に誤ってウェイクアップすると、無効なスレッドIDがに渡されますpthread_join()

コードには別の問題もあります-ミューテックスのロックが解除された後、シグナルされたスレッドが次にウェイクアップするという保証はありません。そのため、2つのスレッドがthread::Exit()すばやく連続して呼び出され、メインスレッドは2番目のスレッドが終了するまで実行されない可能性があります。スレッドを終了すると、ミューテックスのロックが解除されました。この場合pthread_join()、最初のスレッドを呼び出すことはありません。

このような何かがそれらの問題を修正するはずです:

namespace thread {
    int terminate_thread_set = 0;
    pthread_mutex_t terminate_thread = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t terminate_thread_set_cond = PTHREAD_COND_INITIALIZER;
    pthread_cond_t terminate_thread_unset_cond = PTHREAD_COND_INITIALIZER;

    /* ... */

    inline void Exit(void* value)
    {
        pthread_mutex_lock(&thread::terminate_thread);
        while (thread::terminate_thread_set)
            pthread_cond_wait(&thread::terminate_thread_unset_cond);
        thread::terminated_thread_id = pthread_self();
        thread::terminate_thread_set = 1;
        pthread_cond_signal(&thread::terminate_thread_set_cond);
        pthread_mutex_unlock(&thread::terminate_thread);

        pthread_exit(value);
    }
}

とでmain

pthread_mutex_lock(&thread::terminate_thread);

/* ... */

while(thread::total_thread_count > 0) {
    while (!thread::terminate_thread_set)
        pthread_cond_wait(&thread::terminate_thread_set_cond, &thread::terminate_thread);
    thread::terminate_thread_set = 0;
    pthread_join(thread::terminated_thread_id, NULL);
    pthread_cond_signal(&thread::terminate_thread_unset_cond);
...
}
pthread_mutex_unlock(&thread::terminate_thread);

もちろん、他に問題がないというわけではありません。

于 2012-08-05T13:45:45.613 に答える
0

termination_in_process別のスレッドによってロックされていても、メインプロセスからミューテックスのロックを解除しているように見えます。これは未定義の動作です。動作する場合と動作しない場合があります。

解決策は、FIFOバッファー(たとえば、std :: queue、または単にstd :: vector)を使用して、終了したスレッドのスレッドIDをExit()関数内でプッシュし、シグナルを送信して、メインスレッドはバッファを通過し、バッファ内の任意のスレッドに参加します。

セグメンテーション違反の時点で呼び出されない場合Exit()、これが問題の原因ではないはずですが、それでも修正する必要があるかもしれません。

于 2012-08-07T20:36:26.490 に答える
0

これはかなり遅いですが、将来の参考のために投稿するのを忘れました。これが私がそれを修正した方法です:

GCCコンパイラをバージョンから4.5.Xからバージョン4.7.Xにアップグレードし、カーネルを2.6.Xから3.2.Xにアップグレードし、明示的なコンストラクタを提供することで、クラスと静的メンバー変数のグローバル初期化に関するエラーを修正しました。初期化なしでグローバル宣言を許可するため。しかし、必要だったのはGCCコンパイラのアップグレードだけだと思います。

関数の実装が適切ではなかったようです。または、カーネルコードにエラーがありましたか?

于 2012-09-02T06:46:11.137 に答える