外贸网站建设内容包括哪些巩义网络推广外包
在 Linux 系统编程中,嵌套锁(Nested Lock) 通常指允许同一线程多次获取同一个锁的机制(即 递归锁,Recursive Mutex)。这种设计用于解决函数调用链中需要重复加锁的场景(例如递归函数、多层函数嵌套访问共享资源),避免同一线程因重复加锁导致的死锁。以下是详细分析和实现指南:
1. 嵌套锁的核心概念
-
递归加锁:同一线程可以多次对同一锁调用
lock
,但必须调用相同次数的unlock
。 -
锁计数器:递归锁内部维护一个计数器,记录当前线程的加锁次数。
-
应用场景:
-
递归函数访问共享资源。
-
模块化代码中多个函数嵌套调用同一锁。
-
2. Linux 递归锁的实现(POSIX 线程库)
Linux 通过 pthread_mutex
的 递归属性 实现嵌套锁:
步骤 1:设置递归属性
#include <pthread.h>int main() {pthread_mutex_t mutex;pthread_mutexattr_t attr;// 初始化属性对象pthread_mutexattr_init(&attr);// 设置互斥锁类型为递归锁pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);// 使用属性初始化互斥锁pthread_mutex_init(&mutex, &attr);// 销毁属性对象(属性已绑定到锁,后续不再需要)pthread_mutexattr_destroy(&attr);// ... 使用锁 ...pthread_mutex_destroy(&mutex);return 0;
}
步骤 2:递归加锁示例
void recursive_function(pthread_mutex_t *mutex, int depth) {pthread_mutex_lock(mutex); // 第一次加锁if (depth > 0) {recursive_function(mutex, depth - 1); // 递归调用,再次加锁}pthread_mutex_unlock(mutex); // 每次解锁
}int main() {pthread_mutex_t mutex;// 初始化递归锁(代码同上)recursive_function(&mutex, 3); // 嵌套加锁3次,解锁3次pthread_mutex_destroy(&mutex);return 0;
}
3. 嵌套锁的注意事项
(1) 加锁与解锁必须严格配对
-
每次
lock
必须对应一次unlock
,否则其他线程无法获取锁。 -
错误示例:
pthread_mutex_lock(&mutex); // 加锁1 pthread_mutex_lock(&mutex); // 加锁2(合法,因为这是递归锁) pthread_mutex_unlock(&mutex); // 解锁1 // 忘记第二次解锁!锁仍被持有,其他线程将阻塞。
(2) 避免跨线程解锁
-
只有锁的持有者线程可以解锁,其他线程解锁会导致未定义行为。
// 线程A pthread_mutex_lock(&mutex); // 线程B pthread_mutex_unlock(&mutex); // 错误!EPERM 错误
(3) 性能开销
-
递归锁比普通互斥锁略慢(需维护计数器),非必要场景避免滥用。
4. 嵌套锁的典型应用场景
场景 1:递归函数访问共享资源
// 递归遍历链表并修改节点
void traverse_list(Node *node, pthread_mutex_t *mutex) {if (node == NULL) return;pthread_mutex_lock(mutex);modify_node(node); // 修改当前节点traverse_list(node->next, mutex); // 递归调用(再次加锁)pthread_mutex_unlock(mutex);
}
场景 2:模块化代码中的锁传递
// 模块A的函数
void func_a(pthread_mutex_t *mutex) {pthread_mutex_lock(mutex);func_b(mutex); // 调用模块B的函数(需要同一锁)pthread_mutex_unlock(mutex);
}// 模块B的函数
void func_b(pthread_mutex_t *mutex) {pthread_mutex_lock(mutex); // 再次加锁(合法)// 操作共享资源pthread_mutex_unlock(mutex);
}
6. 递归锁与普通锁的对比
特性 | 递归锁 | 普通锁(非递归) |
---|---|---|
同一线程重复加锁 | 允许(计数器递增) | 导致死锁(如 PTHREAD_MUTEX_ERRORCHECK 返回 EDEADLK ) |
性能 | 略低(维护计数器) | 较高 |
适用场景 | 嵌套函数/递归访问共享资源 | 简单临界区 |
7. 综合示例:线程安全的递归目录遍历
#include <stdio.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>pthread_mutex_t mutex;void list_dir(const char *path, int depth) {DIR *dir = opendir(path);if (!dir) return;struct dirent *entry;while ((entry = readdir(dir)) != NULL) {if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)continue;pthread_mutex_lock(&mutex); // 加锁保护打印操作for (int i = 0; i < depth; i++) printf(" ");printf("%s\n", entry->d_name);pthread_mutex_unlock(&mutex);if (entry->d_type == DT_DIR) {char subpath[1024];snprintf(subpath, sizeof(subpath), "%s/%s", path, entry->d_name);list_dir(subpath, depth + 1); // 递归调用,再次加锁}}closedir(dir);
}int main() {pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);pthread_mutex_init(&mutex, &attr);pthread_mutexattr_destroy(&attr);list_dir(".", 0); // 从当前目录开始遍历pthread_mutex_destroy(&mutex);return 0;
}