get_robust_list系统调用及示例

get_robust_list – 获取进程的健壮互斥锁列表

1. 函数介绍

get_robust_list 是一个 Linux 系统调用,用于获取指定进程的健壮互斥锁(robust futex)列表。健壮互斥锁是 Linux 提供的一种特殊类型的 futex,能够在持有锁的进程异常终止时自动清理锁状态,防止其他进程无限期等待。

这个机制主要用于解决多线程程序中,当持有互斥锁的线程意外崩溃时,其他等待该锁的线程可能会永远阻塞的问题。

https://blog.csdn.net/zidier215/article/details/151332225?sharetype=blogdetail&sharerId=151332225&sharerefer=PC&sharesource=zidier215&spm=1011.2480.3001.8118

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: 进程 ID
    • 0: 获取当前进程的健壮列表
    • 正整数: 获取指定进程的健壮列表
  • 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. 健壮互斥锁的工作原理

健壮互斥锁的核心机制:

  1. 列表维护: 每个进程维护一个健壮互斥锁列表
  2. 异常检测: 当持有锁的进程异常终止时,内核检测到
  3. 自动清理: 内核自动将锁标记为”所有者死亡”状态
  4. 状态恢复: 下一个尝试获取锁的线程收到 EOWNERDEAD 错误
  5. 一致性标记: 获得锁的线程必须调用 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 是管理健壮互斥锁的重要系统调用,关键要点:

  1. 健壮性保障: 防止进程崩溃导致的死锁问题
  2. 异常处理: 提供 EOWNERDEAD 机制处理锁所有者死亡情况
  3. 权限控制: 访问其他进程信息需要适当权限
  4. 现代替代: pthread 提供了更高层的健壮互斥锁接口
  5. 系统安全: 需要谨慎使用,避免安全风险

在编写高可靠性多线程程序时,健壮互斥锁是一个重要的同步原语,能够显著提高程序的健壮性。

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注