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()。我还使用了一个未命名的命名空间和一些初始化(如果可能相关的话)。我使用 Code::Blocks 作为 IDE 和 GCC 作为编译器。

4

3 回答 3

1

pthread_cond_wait()允许虚假唤醒,因此您必须在每次唤醒后重新测试条件本身。这可能会导致您的问题 - 如果主线程在设置之前被虚假唤醒thread::terminated_thread_id,它会将无效的线程 id 传递给pthread_join().

您的代码中还有另一个问题 - 无法保证在互斥锁解锁后发出信号的线程将是下一个唤醒的线程,因此两个线程可以thread::Exit()快速连续调用,而主线程直到第二个之后才运行退出线程已解锁互斥锁。在这种情况下,您永远不会调用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 回答