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 的原理。

相关推荐
问道飞鱼20 分钟前
【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现
android·ios·harmonyos·多webview互访
mascon2 小时前
U3D打包IOS的自我总结
ios
名字不要太长 像我这样就好2 小时前
【iOS】继承链
macos·ios·cocoa
karshey3 小时前
【IOS webview】IOS13不支持svelte 样式嵌套
ios
潜龙95273 小时前
第4.3节 iOS App生成追溯关系
macos·ios·cocoa
游戏开发爱好者812 小时前
iOS App 电池消耗管理与优化 提升用户体验的完整指南
android·ios·小程序·https·uni-app·iphone·webview
神策技术社区18 小时前
iOS 全埋点点击事件采集白皮书
大数据·ios·app
wuyoula19 小时前
iOS V2签名网站系统源码/IPA在线签名/全开源版本/亲测
ios
2501_9159184120 小时前
iOS 性能监控工具全解析 选择合适的调试方案提升 App 性能
android·ios·小程序·https·uni-app·iphone·webview
fishycx20 小时前
iOS 构建配置与 AdHoc 打包说明
ios