iOS - 线程与AutoreleasePoolPage

1. AutoreleasePoolPage 结构

objectivec 复制代码
struct AutoreleasePoolPage {
    static pthread_key_t key;      // 只占用一份内存空间
    
    magic_t const magic;
    id *next;
    pthread_t const thread;
    AutoreleasePoolPage *parent;
    AutoreleasePoolPage *child;
    // ...其他成员变量
}

pthread 的 TLS (Thread Local Storage) 机制通过 key-value 映射表实现了这个功能。

2. 基本原理

每个线程都维护着自己的存储空间(类似哈希表),所有线程共享同一个 key,但每个线程的 value 是独立的:

objectivec 复制代码
// pthread 内部实现的简化版本
struct pthread_internal_t {
    // 每个线程都有自己的 specific 数组
    void *specific[PTHREAD_KEYS_MAX];  // 线程特定数据数组
};

// 所有线程共享的键值数组
struct pthread_key_struct {
    bool in_use;                      // 该 key 是否在使用
    void (*destructor)(void *value);  // 析构函数
} pthread_keys[PTHREAD_KEYS_MAX];

3. 关键操作

3.1 创建 key

objectivec 复制代码
// 在 tls_init 中创建 key
void tls_init(void) {
    // pthread_key_create 会在 pthread_keys 数组中分配一个槽位
    AutoreleasePoolPage::key = pthread_key_create(&autoreleasePoolDealloc);
}

3.2 设置线程特定数据

objectivec 复制代码
// 为当前线程设置 page
static void setHotPage(AutoreleasePoolPage *page) {
    // 将 page 存储到当前线程的 specific 数组中
    pthread_setspecific(AutoreleasePoolPage::key, page);
}

3.3 获取线程特定数据

objectivec 复制代码
static inline AutoreleasePoolPage *hotPage() {
    // 从当前线程的 specific 数组中获取 page
    AutoreleasePoolPage *result = (AutoreleasePoolPage *)
        pthread_getspecific(AutoreleasePoolPage::key);
    return result;
}

4. 工作流程示意

objectivec 复制代码
// 简化的内部实现原理
pthread_key_create(key, destructor) {
    // 分配一个全局唯一的 key
    *key = allocate_key_index();
    // 注册析构函数
    pthread_keys[*key].destructor = destructor;
}

pthread_setspecific(key, value) {
    // 获取当前线程
    pthread_internal_t *thread = pthread_self();
    // 将值存储在当前线程的特定位置
    thread->specific[key] = value;
}

pthread_getspecific(key) {
    // 获取当前线程
    pthread_internal_t *thread = pthread_self();
    // 返回当前线程存储的值
    return thread->specific[key];
}

5. 实际应用示例

objectivec 复制代码
// 线程 1
void *thread1_func(void *arg) {
    @autoreleasepool {
        // pthread_getspecific(key) 返回线程1的 page
        AutoreleasePoolPage *page = hotPage();
        // page->thread == thread1
    }
    return NULL;
}

// 线程 2
void *thread2_func(void *arg) {
    @autoreleasepool {
        // pthread_getspecific(key) 返回线程2的 page
        AutoreleasePoolPage *page = hotPage();
        // page->thread == thread2
    }
    return NULL;
}

6. 关键点总结

  1. key 的作用
  • 作为索引,用于在线程的特定数据数组中定位数据
  • 全局唯一,所有线程共享
  1. 线程隔离
  • 每个线程维护独立的存储空间
  • 相同的 key 在不同线程中映射到不同的值
  1. 内存管理
  • 线程退出时自动调用析构函数
  • 自动清理线程特定数据
  1. 性能考虑
  • 快速访问:O(1) 的时间复杂度
  • 空间效率:每个线程只存储使用的数据

这就是为什么使用同一个 key 可以在不同线程中获取不同的 page 的原理。

相关推荐
敲代码的鱼哇2 天前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos
在下历飞雨2 天前
Kuikly基础之状态管理与数据绑定:让“孤寡”计数器动起来
ios·harmonyos
在下历飞雨2 天前
Kuikly基础之Kuikly DSL基础组件实战:构建青蛙主界面
ios·harmonyos
鹏多多.2 天前
flutter-使用fluttertoast制作丰富的高颜值toast
android·前端·flutter·ios
他们都不看好你,偏偏你最不争气2 天前
【iOS】多界面传值
ios
MaoJiu3 天前
Flutter混合开发:在iOS工程中嵌入Flutter Module
flutter·ios
2501_915921433 天前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
2501_916008893 天前
uni-app iOS 文件管理与 itools 配合实战,多工具协作的完整流程
android·ios·小程序·https·uni-app·iphone·webview
Digitally3 天前
如何将视频从 iPhone 转移到 Mac
macos·ios·iphone
2501_916007473 天前
uni-app iOS 文件调试常见问题与解决方案:结合 itools、克魔、iMazing 的实战经验
android·ios·小程序·https·uni-app·iphone·webview