get_robust_list – 获取进程的健壮互斥锁列表
1. 函数介绍
get_robust_list
是一个 Linux 系统调用,用于获取指定进程的健壮互斥锁(robust futex)列表。健壮互斥锁是 Linux 提供的一种特殊类型的 futex,能够在持有锁的进程异常终止时自动清理锁状态,防止其他进程无限期等待。
这个机制主要用于解决多线程程序中,当持有互斥锁的线程意外崩溃时,其他等待该锁的线程可能会永远阻塞的问题。
2. 函数原型
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
long get_robust_list(int pid, struct robust_list_head **head_ptr, size_t *len_ptr);
注意:该函数不是标准 C 库的一部分,需要通过
syscall()
调用。
3. 功能
获取指定进程的健壮互斥锁列表信息。返回的信息包括指向健壮列表头的指针和列表的长度。
4. 参数
int pid
: 进程 ID0
: 获取当前进程的健壮列表- 正整数: 获取指定进程的健壮列表
struct robust_list_head **head_ptr
: 指向指针的指针,用于接收健壮列表头的地址size_t *len_ptr
: 指向 size_t 的指针,用于接收列表长度
5. robust_list_head 结构体定义
struct robust_list {
struct robust_list *next;
};
struct robust_list_head {
struct robust_list list;
long futex_offset;
unsigned long list_op_pending;
};
6. 返回值
- 成功时返回 0
- 失败时返回 -1,并设置
errno
7. 常见 errno 错误码
EPERM
: 权限不足(尝试获取其他进程信息时需要适当权限)ESRCH
: 指定的进程不存在EINVAL
: 无效的参数EFAULT
: 指针参数指向无效内存地址ENOSYS
: 系统不支持该功能
8. 相似函数,或关联函数
set_robust_list()
: 设置当前进程的健壮互斥锁列表futex()
: futex 系统调用pthread_mutexattr_setrobust()
: 设置 pthread 互斥锁为健壮类型pthread_mutex_consistent()
: 标记健壮互斥锁为一致状态/proc/[pid]/maps
: 查看进程内存映射/proc/[pid]/status
: 查看进程状态信息
9. 示例代码
示例1:基本使用 – 获取当前进程的健壮列表
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <errno.h>
#include <string.h>
#ifndef SYS_get_robust_list
# define SYS_get_robust_list 275 // x86_64 架构下的系统调用号
#endif
int main() {
struct robust_list_head *head;
size_t len;
long result;
printf("=== 获取当前进程的健壮互斥锁列表 ===\n");
printf("当前进程 PID: %d\n", getpid());
// 获取当前进程的健壮列表
result = syscall(SYS_get_robust_list, 0, &head, &len);
if (result == -1) {
printf("get_robust_list 调用失败\n");
printf("errno = %d: %s\n", errno, strerror(errno));
switch (errno) {
case EPERM:
printf("权限不足\n");
break;
case ENOSYS:
printf("系统不支持健壮互斥锁功能\n");
break;
default:
printf("其他错误\n");
break;
}
return 1;
}
printf("成功获取健壮列表信息:\n");
printf(" 列表头地址: %p\n", (void*)head);
printf(" 列表长度: %zu 字节\n", len);
if (head == NULL) {
printf(" 当前进程没有设置健壮列表\n");
} else {
printf(" 已设置健壮列表\n");
}
return 0;
}
示例2:健壮互斥锁的实际使用
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#ifndef SYS_get_robust_list
# define SYS_get_robust_list 275
#endif
#ifndef SYS_set_robust_list
# define SYS_set_robust_list 275
#endif
pthread_mutex_t robust_mutex = PTHREAD_MUTEX_INITIALIZER;
void* worker_thread(void *arg) {
int thread_id = *(int*)arg;
int ret;
printf("线程 %d: 尝试获取健壮互斥锁\n", thread_id);
ret = pthread_mutex_lock(&robust_mutex);
if (ret == EOWNERDEAD) {
printf("线程 %d: 检测到锁持有者已死亡\n", thread_id);
printf("线程 %d: 标记互斥锁为一致状态\n", thread_id);
pthread_mutex_consistent(&robust_mutex);
} else if (ret != 0) {
printf("线程 %d: 获取锁失败: %s\n", thread_id, strerror(ret));
return NULL;
}
printf("线程 %d: 成功获取锁,执行临界区代码\n", thread_id);
// 模拟一些工作
sleep(2);
printf("线程 %d: 释放锁\n", thread_id);
pthread_mutex_unlock(&robust_mutex);
return NULL;
}
void check_robust_list() {
struct robust_list_head *head;
size_t len;
long result;
result = syscall(SYS_get_robust_list, 0, &head, &len);
if (result == 0) {
printf("健壮列表状态:\n");
printf(" 列表头: %p\n", (void*)head);
printf(" 长度: %zu 字节\n", len);
}
}
int main() {
pthread_t thread1, thread2;
int id1 = 1, id2 = 2;
int ret;
printf("=== 健壮互斥锁演示 ===\n");
// 设置互斥锁为健壮类型
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
pthread_mutex_init(&robust_mutex, &attr);
printf("已创建健壮互斥锁\n");
check_robust_list();
// 创建第一个线程
ret = pthread_create(&thread1, NULL, worker_thread, &id1);
if (ret != 0) {
printf("创建线程1失败: %s\n", strerror(ret));
return 1;
}
// 等待一段时间,让第一个线程获取锁
sleep(1);
// 创建第二个线程
ret = pthread_create(&thread2, NULL, worker_thread, &id2);
if (ret != 0) {
printf("创建线程2失败: %s\n", strerror(ret));
return 1;
}
// 等待线程完成
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("所有线程执行完成\n");
check_robust_list();
// 清理
pthread_mutex_destroy(&robust_mutex);
pthread_mutexattr_destroy(&attr);
return 0;
}
示例3:获取其他进程的健壮列表信息
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#ifndef SYS_get_robust_list
# define SYS_get_robust_list 275
#endif
void check_process_robust_list(pid_t pid) {
struct robust_list_head *head;
size_t len;
long result;
printf("检查进程 %d 的健壮列表:\n", pid);
result = syscall(SYS_get_robust_list, pid, &head, &len);
if (result == -1) {
printf(" 获取失败: %s\n", strerror(errno));
switch (errno) {
case EPERM:
printf(" 权限不足,无法查看其他进程信息\n");
break;
case ESRCH:
printf(" 进程不存在\n");
break;
default:
break;
}
} else {
printf(" 成功获取信息:\n");
printf(" 列表头地址: %p\n", (void*)head);
printf(" 列表长度: %zu 字节\n", len);
if (head == NULL) {
printf(" 该进程未设置健壮列表\n");
} else {
printf(" 该进程已设置健壮列表\n");
}
}
printf("\n");
}
int main() {
pid_t child_pid;
int status;
printf("=== 进程健壮列表检查 ===\n");
// 检查当前进程
check_process_robust_list(0); // 当前进程
// 检查 init 进程
check_process_robust_list(1);
// 创建子进程进行测试
child_pid = fork();
if (child_pid == -1) {
perror("fork 失败");
return 1;
}
if (child_pid == 0) {
// 子进程
printf("子进程 PID: %d\n", getpid());
// 子进程睡眠一段时间
sleep(5);
exit(0);
} else {
// 父进程
printf("父进程 PID: %d\n", getpid());
printf("子进程 PID: %d\n", child_pid);
// 检查子进程
sleep(1); // 等待子进程启动
check_process_robust_list(child_pid);
// 等待子进程结束
waitpid(child_pid, &status, 0);
printf("子进程已结束\n");
// 再次检查已结束的进程
check_process_robust_list(child_pid);
}
return 0;
}
10. 健壮互斥锁的工作原理
健壮互斥锁的核心机制:
- 列表维护: 每个进程维护一个健壮互斥锁列表
- 异常检测: 当持有锁的进程异常终止时,内核检测到
- 自动清理: 内核自动将锁标记为”所有者死亡”状态
- 状态恢复: 下一个尝试获取锁的线程收到
EOWNERDEAD
错误 - 一致性标记: 获得锁的线程必须调用
pthread_mutex_consistent()
标记锁为一致状态
11. pthread 健壮互斥锁使用示例
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
pthread_mutex_t robust_mutex;
void setup_robust_mutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
pthread_mutex_init(&robust_mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
void use_robust_mutex(int thread_id) {
int ret;
ret = pthread_mutex_lock(&robust_mutex);
switch (ret) {
case 0:
printf("线程 %d: 成功获取锁\n", thread_id);
break;
case EOWNERDEAD:
printf("线程 %d: 检测到锁所有者死亡\n", thread_id);
// 检查数据一致性并恢复
// ... 数据恢复代码 ...
pthread_mutex_consistent(&robust_mutex);
printf("线程 %d: 锁状态已恢复\n", thread_id);
break;
case ENOTRECOVERABLE:
printf("线程 %d: 锁不可恢复,需要重新初始化\n", thread_id);
pthread_mutex_destroy(&robust_mutex);
setup_robust_mutex();
return;
default:
printf("线程 %d: 获取锁失败: %s\n", thread_id, strerror(ret));
return;
}
// 临界区代码
printf("线程 %d: 执行临界区操作\n", thread_id);
sleep(1);
pthread_mutex_unlock(&robust_mutex);
printf("线程 %d: 释放锁\n", thread_id);
}
12. 实际应用场景
健壮互斥锁主要用于:
- 多进程共享内存: 防止进程崩溃导致其他进程死锁
- 关键系统服务: 提高系统稳定性和可靠性
- 数据库系统: 保护共享数据结构
- 实时系统: 确保系统的可预测性
- 高可用性应用: 减少单点故障影响
总结
get_robust_list
是管理健壮互斥锁的重要系统调用,关键要点:
- 健壮性保障: 防止进程崩溃导致的死锁问题
- 异常处理: 提供
EOWNERDEAD
机制处理锁所有者死亡情况 - 权限控制: 访问其他进程信息需要适当权限
- 现代替代: pthread 提供了更高层的健壮互斥锁接口
- 系统安全: 需要谨慎使用,避免安全风险
在编写高可靠性多线程程序时,健壮互斥锁是一个重要的同步原语,能够显著提高程序的健壮性。