在一个pthread_once方法内又再次调用了这个pthread_once导致死锁。
分析下这个pthread_once的源码:
可以看到这个pthread_once_t结构体就是一个整形数字加自旋锁。
int
___pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
{/* Fast path. See __pthread_once_slow. */int val;val = atomic_load_acquire (once_control);if (__glibc_likely ((val & __PTHREAD_ONCE_DONE) != 0)) // 这里判断如果已经执行完成就返回0return 0;elsereturn __pthread_once_slow (once_control, init_routine);
}
static int
__attribute__ ((noinline))
__pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void))
{while (1){int val, newval;/* CAS把状态改为__PTHREAD_ONCE_INPROGRESS *//* We need acquire memory order for this load because if the valuesignals that initialization has finished, we need to see anydata modifications done during initialization. */val = atomic_load_acquire (once_control);do{/* Check if the initialization has already been done. */if (__glibc_likely ((val & __PTHREAD_ONCE_DONE) != 0))return 0;/* We try to set the state to in-progress and having the currentfork generation. We don't need atomic accesses for the forkgeneration because it's immutable in a particular process, andforked child processes start with a single thread that modifiedthe generation. */newval = __fork_generation | __PTHREAD_ONCE_INPROGRESS;/* We need acquire memory order here for the same reason as for theload from once_control above. */}while (__glibc_unlikely (!atomic_compare_exchange_weak_acquire (once_control, &val, newval)));/* Check if another thread already runs the initializer. */if ((val & __PTHREAD_ONCE_INPROGRESS) != 0){/* 修改失败,说明其他线程在修改,直接等待 *//* Check whether the initializer execution was interrupted by afork. We know that for both values, __PTHREAD_ONCE_INPROGRESSis set and __PTHREAD_ONCE_DONE is not. */if (val == newval){/* Same generation, some other thread was faster. Wait andretry. */futex_wait_simple ((unsigned int *) once_control,(unsigned int) newval, FUTEX_PRIVATE);continue;}}/* This thread is the first here. Do the initialization.Register a cleanup handler so that in case the thread getsinterrupted the initialization can be restarted. */pthread_cleanup_combined_push (clear_once_control, once_control);/* 调用用户传入的方法 */init_routine ();pthread_cleanup_combined_pop (0);/* Mark *once_control as having finished the initialization. We needrelease memory order here because we need to synchronize with otherthreads that want to use the initialized data. *//* 修改状态为__PTHREAD_ONCE_DONE */atomic_store_release (once_control, __PTHREAD_ONCE_DONE);/* Wake up all other threads. *//* 唤醒其他线程 */futex_wake ((unsigned int *) once_control, INT_MAX, FUTEX_PRIVATE);break;}return 0;
}