关于PTHREAD_MUTEX_RECURSIVE的问题:被其他线程锁定时发生阻塞
关于PTHREAD_MUTEX_RECURSIVE阻塞问题的解析与解决
嘿,我来帮你捋清楚这个问题!首先得纠正一个很容易踩的误区:递归互斥锁(PTHREAD_MUTEX_RECURSIVE)并不是让多个线程都能随便加锁的“万能锁”——它的核心作用只是允许同一个线程对同一把锁多次加锁而不会死锁,但不同线程之间的互斥性和普通锁完全一样。所以当其他线程已经持有这把锁时,你的线程尝试加锁被阻塞是完全正常的行为,这不是bug,是递归锁的设计本意。
再看你贴的代码片段,main函数里的pthread_mutexat...明显没写完,大概率是漏掉了设置锁类型的关键步骤?如果没把锁属性设置为递归类型,那你的锁本质还是普通的互斥锁,连同一线程多次加锁都会死锁,更别说线程间的情况了。
补全正确的递归锁使用代码
下面是完整的可运行示例,你可以看看递归锁的正确用法,以及线程间互斥的正常表现:
#include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t m; pthread_mutexattr_t ma; void* exec_th(void* arg) { printf("THREAD %p 准备加锁\n", pthread_self()); // 其他线程持有锁时,这里会阻塞——不管是不是递归锁 pthread_mutex_lock(&m); printf("THREAD %p 第一次加锁成功\n", pthread_self()); // 递归锁的核心特性:同一线程可以再次加锁,不会死锁 pthread_mutex_lock(&m); printf("THREAD %p 第二次加锁成功(递归锁生效)\n", pthread_self()); // 划重点:加了几次锁就要解锁几次,少一次都不行! pthread_mutex_unlock(&m); pthread_mutex_unlock(&m); printf("THREAD %p 解锁完成\n", pthread_self()); return (void*)0; } int main() { // 初始化锁属性 pthread_mutexattr_init(&ma); // 必须设置为递归锁类型,这一步千万别忘! pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); // 用属性初始化互斥锁 pthread_mutex_init(&m, &ma); pthread_t th1, th2; pthread_create(&th1, NULL, exec_th, NULL); // 先让th1拿到锁,再启动th2,就能看到th2被阻塞的过程 sleep(1); pthread_create(&th2, NULL, exec_th, NULL); pthread_join(th1, NULL); pthread_join(th2, NULL); // 清理资源 pthread_mutex_destroy(&m); pthread_mutexattr_destroy(&ma); return 0; }
几个必须记住的关键点
- 递归锁不打破线程间互斥:它只解决同一线程多次加锁的死锁问题,不同线程之间该阻塞还是会阻塞,这是正常的同步逻辑。
- 一定要正确初始化属性:如果没调用
pthread_mutexattr_settype设置PTHREAD_MUTEX_RECURSIVE,你的锁就是默认的普通锁,同一线程多次加锁直接死锁。 - 解锁次数要和加锁次数匹配:递归锁被加了N次,就必须解锁N次,否则其他线程永远拿不到锁。
如果你的需求是让多个线程同时访问某个资源,那递归锁根本不是正确的选择,你应该考虑读写锁(pthread_rwlock_t)或者其他适合并发访问的同步机制哦。
内容的提问来源于stack exchange,提问作者torae
相关产品推荐
相关产品推荐

