当前位置: 首页 > ai >正文

【中间件】bthread_数据结构_学习笔记

bthread数据结构

  • bthread_数据结构_学习笔记
    • 1 pthread_cond_t
      • 1.1 definition
      • 1.2 解释
      • 1.3 设计动机
      • 1.4 使用示例
      • 1.5 注意事项
      • 1.6 进一步延伸:pthread_cond_s
    • 2 pthread_mutex_t

bthread_数据结构_学习笔记

1 pthread_cond_t

POSIX线程库 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h
底层通过union实现,系统编程中“隐藏实现细节,暴露稳定接口”的经典范例。

主要目的是为了兼容不同平台的底层实现差异,同时确保类型的内存布局和对齐方式符合规范。

  • 类型抽象:隐藏平台差异,提供统一接口。
  • 内存安全:固定大小和强制对齐避免常见错误。
  • 灵活初始化:支持静态和动态初始化方式。

1.1 definition

typedef union {struct __pthread_cond_s __data;   // 实际存储条件变量数据的结构体char __size[__SIZEOF_PTHREAD_COND_T]; // 保证联合体大小与平台实现一致__extension__ long long int __align;  // 强制对齐(通常是 8 字节对齐)
} pthread_cond_t;

1.2 解释

  1. struct __pthread_cond_s __data

    • 包含条件变量的实际数据(如等待队列、计数器等),具体字段由底层实现定义。
    • 开发者通常不直接操作此结构体,而是通过 pthread_cond_* 系列函数(如 pthread_cond_init, pthread_cond_wait)间接使用。
  2. char __size[__SIZEOF_PTHREAD_COND_T]

    • 用于确保联合体的总大小与平台实现的 pthread_cond_t 一致。
    • __SIZEOF_PTHREAD_COND_T 是一个宏,表示目标平台上 pthread_cond_t 的字节数,由编译器或系统头文件提供。
  3. long long int __align

    • 强制联合体按 long long(通常 8 字节)对齐,避免内存对齐问题。
    • __extension__ 是 GCC 扩展语法,用于忽略编译器的严格标准检查。

1.3 设计动机

  1. 跨平台兼容性

    • 不同操作系统或硬件架构对 pthread_cond_t 的实现可能不同(如字段顺序、对齐要求)。
    • 通过联合体将实现细节隐藏在 __data 结构体中,用户只需使用 pthread_cond_t 类型,无需关心底层差异。
  2. 固定内存布局

    • __size 数组确保联合体的大小严格等于 __SIZEOF_PTHREAD_COND_T,避免用户误分配不足内存。
    • 例如,静态初始化条件变量时,用户可以直接用 PTHREAD_COND_INITIALIZER 宏,而无需知道具体结构。
  3. 对齐控制

    • __align 成员确保联合体按最大对齐要求(如 8 字节)分配内存,防止因对齐不当导致的性能问题或硬件异常。

1.4 使用示例

// 静态初始化(依赖联合体的大小和对齐)
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;// 动态初始化
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);// 使用条件变量
pthread_cond_wait(&cond, &mutex);

1.5 注意事项

  • 不要直接操作 __data 成员
    条件变量的内部结构是平台相关的,直接访问可能导致不可移植或未定义行为。

  • 依赖标准函数
    始终使用 pthread_cond_* 函数操作条件变量,而非手动修改联合体成员。

  • 内存对齐
    联合体的对齐机制确保了跨平台安全性,但用户仍需避免将 pthread_cond_t 放置在不对齐的内存地址。


1.6 进一步延伸:pthread_cond_s

Linux 系统中 POSIX 条件变量 pthread_cond_t 的底层实现。是 Linux 高效线程同步的核心,通过原子计数器、分组策略和引用机制,平衡了性能与正确性。理解其字段有助于:

  • 调试复杂的线程竞争问题。
  • 编写高性能的多线程代码(如避免不必要的广播)。
  • 深入操作系统级并发原语的实现原理。

它的字段设计用于高效管理线程的等待与唤醒机制,同时确保线程安全和性能。

definition

struct __pthread_cond_s {__atomic_wide_counter __wseq;     // 全局等待序列号(原子计数器)__atomic_wide_counter __g1_start; // 第一组(Group 1)的起始序列号(原子计数器)unsigned int __g_refs[2];  __LOCK_ALIGNMENT       // 组的引用计数(每个组对应一个槽)unsigned int __g_size[2];         // 组的大小(跟踪每个组的等待线程数)unsigned int __g1_orig_size;      // Group 1 的原始大小(用于广播操作)unsigned int __wrefs;             // 等待者的引用计数(防止销毁时竞争)unsigned int __g_signals[2];      // 组的待处理信号数(唤醒信号计数)
} __LOCK_ALIGNMENT;                   // 结构体对齐(通常与锁对齐一致)

字段详细说明

  1. __atomic_wide_counter __wseq

    • 作用:全局等待序列号,原子计数器。
    • 细节
      • 每个线程在调用 pthread_cond_wait 进入等待前会递增此值,表示一次新的等待事件。
      • 用于唯一标识等待操作的顺序,避免唤醒操作(如 pthread_cond_signalpthread_cond_broadcast)遗漏或重复。
  2. __atomic_wide_counter __g1_start

    • 作用:第一组(Group 1)的起始等待序列号。
    • 细节
      • 条件变量将等待线程划分为两个组(Group 1 和 Group 2),以减少竞争。
      • __g1_start 记录 Group 1 的起始序列号,当 Group 1 的线程全部被唤醒后,Group 2 会晋升为新的 Group 1。
  3. unsigned int __g_refs[2]

    • 作用:每个组的引用计数,用于跟踪活跃的等待线程数。
    • 细节
      • 索引 0 对应 Group 1,索引 1 对应 Group 2。
      • 线程进入等待时会增加对应组的引用计数,唤醒后减少。
      • 防止在唤醒操作过程中组被错误回收。
  4. unsigned int __g_size[2]

    • 作用:每个组的当前等待线程数。
    • 细节
      • __g_refs 配合使用,确保唤醒操作(如 pthread_cond_broadcast)能正确统计需要唤醒的线程数量。
      • 例如,pthread_cond_broadcast 会唤醒某个组的所有线程,__g_size 用于确定唤醒的数量。
  5. unsigned int __g1_orig_size

    • 作用:Group 1 的原始大小,用于广播操作。
    • 细节
      • 在调用 pthread_cond_broadcast 时,会记录 Group 1 的初始大小,确保所有在广播前进入等待的线程都被唤醒。
      • 避免广播过程中新加入的线程被错误唤醒。
  6. unsigned int __wrefs

    • 作用:等待者的引用计数。
    • 细节
      • 跟踪当前正在等待的线程总数(包括所有组)。
      • 在销毁条件变量(pthread_cond_destroy)时,需确保 __wrefs 为 0,防止有线程仍在等待时销毁资源。
  7. unsigned int __g_signals[2]

    • 作用:每个组的待处理唤醒信号数。
    • 细节
      • 当调用 pthread_cond_signalpthread_cond_broadcast 时,信号会被记录到对应组的 __g_signals 中。
      • 等待线程被唤醒前会检查此值,确保每个信号只唤醒一个线程(避免“惊群效应”)。
  8. __LOCK_ALIGNMENT

    • 作用:结构体对齐标记。

    • 细节

      • 通常与系统锁(如 pthread_mutex_t)的对齐方式一致,确保条件变量和互斥锁在内存中正确对齐,避免性能下降或硬件异常。
      • 处理器访问内存时,若数据的地址是某个值的整数倍(如4字节对齐的地址为4的倍数),则访问效率更高。
      • 未对齐的访问可能导致:
        • 性能下降:处理器可能需要多次内存操作来读取或写入未对齐的数据。
        • 硬件异常:在某些架构(如ARM或SPARC)上,未对齐访问会直接触发错误。
        • 原子操作失败:同步原语(如锁)依赖原子指令,未对齐的结构体可能导致指令无法正确执行。
    • 平台兼容性

      • 不同硬件架构(如x86、ARM、RISC-V)的对齐要求可能不同。例如:
        • x86 允许未对齐访问(但性能较低)。
        • ARMv7 要求严格对齐,否则触发总线错误。
    • __LOCK_ALIGNMENT 通过宏定义适配目标平台的对齐要求,例如:#define __LOCK_ALIGNMENT __attribute__((aligned(8))) // 8字节对齐确保结构体在所有平台上均按硬件要求对齐。

    • 优化内存访问

      • 对齐后的结构体字段排列更紧凑,减少填充(Padding)字节,节省内存。
      • 对齐的字段可被处理器单次内存操作访问,提升指令执行效率。
    • 支持原子操作

      • 条件变量的实现依赖原子计数器(如 __atomic_wide_counter)。
      • 原子操作指令(如CAS, LL/SC)通常要求操作数对齐。未对齐的原子操作可能失败或不可用。
    • __LOCK_ALIGNMENT 确保原子字段(如 __wseq、__g1_start)按原子指令的要求对齐。

    • 作用归纳:

      • 兼容性:适配不同硬件平台的对齐要求。
      • 性能优化:减少伪共享、提升内存访问效率。
      • 正确性:确保原子操作和同步机制可靠工作。
      • 协作安全:与互斥锁对齐一致,避免协同使用时的潜在问题。
    • 系统级编程中“显式控制内存布局”的典范,确保了多线程同步原语的高效与稳定.

组(Group)机制
条件变量通过 分组策略 优化唤醒操作:

  1. Group 1 和 Group 2
    • Group 1 是当前活跃的等待组,新线程在等待时加入 Group 1。
    • 当 Group 1 的线程被全部唤醒后,Group 2 晋升为新的 Group 1,避免操作同一组时的竞争。
  2. 广播(Broadcast)优化
    • pthread_cond_broadcast 会唤醒 Group 1 的所有线程,同时记录 __g1_orig_size 确保只唤醒广播前的等待线程。
  3. 信号分发
    • pthread_cond_signal 优先唤醒 Group 1 的线程,若 Group 1 无等待线程,则唤醒 Group 2。

关键操作流程

  1. 等待操作(pthread_cond_wait

    • 线程递增 __wseq 进入等待队列。
    • 根据当前组策略(Group 1 或 Group 2)更新 __g_refs__g_size
    • 检查 __g_signals,若无待处理信号,则阻塞线程。
  2. 唤醒单个线程(pthread_cond_signal

    • 检查 Group 1 的 __g_size,若有等待线程,递增 __g_signals[0] 并唤醒一个线程。
    • 若 Group 1 无等待线程,则对 Group 2 执行相同操作。
  3. 唤醒所有线程(pthread_cond_broadcast

    • 记录 __g1_orig_size 为当前 Group 1 的大小。
    • __g_signals[0] 设为 __g1_orig_size,唤醒所有 Group 1 的线程。
    • Group 1 的线程唤醒后,__g_refs[0]__g_size[0] 被清零,Group 2 晋升为新 Group 1。

优势

  1. 减少锁竞争
    • 通过分组机制将唤醒操作分散到不同组,降低多核环境下的锁争用。
  2. 避免信号丢失
    • 原子计数器和序列号确保每个等待线程都能被正确追踪。
  3. 高效广播
    • __g1_orig_size__g_signals 的配合使广播操作无需遍历队列,直接通过计数器批量唤醒。
  4. 内存安全
    • __wrefs 防止条件变量在销毁时仍有线程等待。

示例场景
假设一个生产者-消费者模型:

  • 消费者线程 调用 pthread_cond_wait 进入等待,加入 Group 1,递增 __wseq__g_refs[0]__g_size[0]
  • 生产者线程 调用 pthread_cond_signal,发现 Group 1 的 __g_size[0] > 0,递增 __g_signals[0] 并唤醒一个消费者。
  • 唤醒的消费者递减 __g_refs[0]__g_size[0],继续执行任务。

2 pthread_mutex_t

http://www.xdnf.cn/news/3259.html

相关文章:

  • 线段树原理和代码详解
  • JavaScript基础-递增和递减运算符
  • 二、HTML
  • PostgreSQL数据表操作SQL
  • C标准库(libc)接口及示例解析
  • 从股指到期指,哪些因素影响基差?
  • 51c嵌入式~单片机~合集9
  • [操作系统] 线程互斥
  • 【Linux知识】Shell脚本中各类参数传递以及获取
  • Elastic Search 的安装、使用方式
  • 【分享】deepseek 超强ai助手 1.1.8最新版 不卡顿
  • Python字典(dict)详解:从创建到操作全掌握
  • Anaconda中配置Pyspark的Spark开发环境
  • 使用listPersonalCertificates 命令列示WebSphere Application Server特定密钥库中的个人证书
  • 【Android】四大组件之ContentProvider
  • 比较图检索增强生成(Graph RAG)和向量检索增强生成(Vector RAG)
  • L3-041 影响力
  • 如何在Cursor中使用MCP服务
  • Leetcode刷题记录24——最大子数组和
  • Java SE(6)——类和对象
  • 数据库 AI 助手测评:Chat2DB、SQLFlow 等工具如何提升开发效率?
  • 手搓传染病模型(SEIAR)
  • python3GUI--视频监控管理平台 By:PyQt5(详细讲解)
  • 多商户商城系统开发全策略:从技术架构到流量增长
  • python如何word转pdf
  • Node.js心得笔记
  • 前端八股 6
  • Redis ⑧-RESP | 渐进式遍历 | 数据库管理
  • 移动光猫 UNG853H 获取超级管理员账号密码
  • 2025东三省C题深圳杯C题数学建模挑战赛数模思路代码文章教学: 分布式能源接入配电网的风险分析