pthread_cond_wait:随机分段错误

更新3

最近,我注意到我的代码随机导致Segmentation Fault错误。 但我认为到目前为止我的代码非常简单,我无法弄清楚错误的来源。 由于它是随机发生的,我认为存在某种竞争条件。 我认为这是可能相关的所有代码,如果您需要更多,请告诉我:

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作为编译器。

允许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); 

当然,这并不是说你没有其他问题。

看起来好像是从主进程解锁你的termination_in_process互斥锁 – 即使它被另一个线程锁定 – 这是未定义的行为。 它可能有用,也可能不起作用。

一个解决方案可能是使用FIFO缓冲区(例如std :: queue ,甚至只是std :: vector )并在Exit()函数中将终止线程的线程id推送到它,然后发出你的信号,让主线程通过缓冲区并加入其中的任何线程。

如果在segfault点没有调用Exit() ,这不应该是你的问题的原因,但它仍然是你可能想要解决的问题。

这已经很晚了,但我忘了发布以备将来参考。 这就是我修复它的方法:

我将我的GCC编译器从版本升级到4.5.X到版本4.7.X以及我的内核从2.6.X升级到3.2.X并通过提供显式构造函数修复了关于类的全局实例化和静态成员变量的一些错误为了在没有初始化的情况下允许全局声明。 但我认为升级GCC编译器就是所需要的。

看起来该function的实现不合适。 或者内核代码中有一些错误?