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

相关推荐
忆江南9 小时前
iOS 深度解析
flutter·ios
没有故事的Zhang同学9 小时前
05-主题|事件响应者链@iOS-应用场景与进阶实践
ios
FeliksLv17 小时前
尝试给Lookin 支持 MCP
ios
没有故事的Zhang同学17 小时前
01-研究系统框架@Web@iOS | JavaScriptCore 框架:从使用到原理解析
ios
CocoaKier2 天前
苹果谷歌商店:如何监控并维护用户评分评论
ios·google·apple
iOS日常2 天前
iOS设备崩溃日志获取与查看
ios·xcode
wangruofeng3 天前
AI 助力 Flutter 3.27 升级到 3.38 完整指南:两周踩坑与实战复盘
flutter·ios·ai编程
iOS日常3 天前
Xcode 垃圾清理
ios·xcode
开心就好20253 天前
不越狱能抓到 HTTPS 吗?在未越狱 iPhone 上抓取 HTTPS
后端·ios
傅里叶4 天前
iOS相机权限获取
flutter·ios