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

相关推荐
游戏开发爱好者83 小时前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
黑码哥3 小时前
ViewHolder设计模式深度剖析:iOS开发者掌握Android列表性能优化的实战指南
android·ios·性能优化·跨平台开发·viewholder
2501_915106325 小时前
app 上架过程,安装包准备、证书与描述文件管理、安装测试、上传
android·ios·小程序·https·uni-app·iphone·webview
2501_915106325 小时前
使用 Sniffmaster TCP 抓包和 Wireshark 网络分析
网络协议·tcp/ip·ios·小程序·uni-app·wireshark·iphone
熊猫钓鱼>_>5 小时前
移动端开发技术选型报告:三足鼎立时代的开发者指南(2026年2月)
android·人工智能·ios·app·鸿蒙·cpu·移动端
徐同保1 天前
通过ip访问nginx的服务时,被第一个server重定向了,通过设置default_server解决这个问题
ios·iphone
2501_915918411 天前
在 iOS 环境下查看 App 详细信息与文件目录
android·ios·小程序·https·uni-app·iphone·webview
2501_916007471 天前
没有 Mac 用户如何上架 App Store,IPA生成、证书与描述文件管理、跨平台上传
android·macos·ios·小程序·uni-app·iphone·webview
夏幻灵2 天前
HTTPS全面解析:原理、加密机制与证书体
ios·iphone
TheNextByte12 天前
如何在iPhone上恢复已删除的笔记的综合指南
笔记·ios·iphone