pthread_cleanup_push注册清理函数中解锁导致的时间窗口问题

可以向其他线程发送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这个函数最好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值