可以向其他线程发送pthread_cancel(threadid) ,让线程id为threadid的另一个线程取消,若threadid这个线程中使用了mutex,在lock和unlock期间收到了其他线程发来的取消要求,那么这个mutex没人解锁,造成死锁,解决这个问题的方案是注册线程清理函数,在清理函数中释放资源(解锁),但这样会造成一个时间窗口导致的额外加锁或者额外解锁,如下:
pthread_mutex_t mutex;
void cleanup_func(void* arg) {
pthread_mutex_unlock(&mutex);
}
void* thread_func(void* arg) {
pthread_mutex_lock(&mutex);
/*
* here is a time window, other thread call pthread_cancel cause
* unlock twice
*/
pthread_cleanup_push(cleanup_func);
pthread_exit(NULL);
pthread_cleanup_pop(0);
}
int main() {
pthread_t threadid;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_create(&threadid, NULL, thread_func, NULL);
pthread_join(threadid, NULL);
exit(0);
}
在线程函数thread_func中,先加锁,然后再注册清理函数,这里会有问题,在加锁后清理函数之前,有一个时间窗口,若此时其他线程向其发送pthread_cancel,会导致线程直接终止,对于mutex,没人解锁。先注册再lock也不行,如下:
void* thread_func(void* arg) {
pthread_cleanup_push(clean_func);
/*
* here is a time window
*/
pthread_mutex_lock(&mutex);
...
}
在注册清理函数之后,锁mutex之前,其他线程发来pthread_cancel,会导致额外解锁了mutex一次。
综上,对于这个时间窗口的问题,内核并没有提供相应的原子处理方案,由于mutex的实现是允许多次unlock,所以为了防止死锁,选择先注册清理函数,再锁mutex。当然能够不使用pthread_cancel这个函数最好