iOS 系统通过 Core Services 层的 Foundation 框架提供基于 OC 语言的 NSThread 和 NSOperationQueue 类来实现对线程和线程池的管理和使用. 同时也提供了一套基于 C 语言的 GCD 线程池函数库来支持多线程的处理应用. 这些高级的线程类或者函数的内部实现大部分最终都会调用 POSIX 标准中的 pthread 线程库中的 pthread_xxx 系列函数 (#include <pthread.h>) 来完成线程的创建, 运行, 暂停, 恢复, 销毁, 结束等操作. 用户态下的线程创建通过系统调用到达内核态的 BSD 层并创建 bsdthread 对象, 而 BSD 层则调用 Mach 层的 ksthread 对象来完成最终线程的创建和调度的.
线程架构图
pthread 库中除了提供一系列标准的线程操作 API 外, 还提供了一个用于监控线程创建, 运行, 结束, 销毁的内省函数(单词 introspection 翻译为内省, 但我觉得叫拦截器可能更好一些). 这个函数定义在头文件 #include <pthread/introspection.h > 中, 函数的签名为:
pthread_introspection_hook_t pthread_introspection_hook_install(pthread_introspection_hook_t hook)
函数的作用是安装一个回调函数来挂钩线程生命周期的四个过程. 因此函数的入参是一个函数指针, 返回的则是老的挂钩函数的指针. 回调函数是一个格式为 pthread_introspection_hook_t 类型的函数, 其格式定义如下:
typedef void (*pthread_introspection_hook_t)(unsigned int event, pthread_t thread, void *addr, size_t size);
回调函数的每个参数的意义如下:
event: 指定线程所处的状态.
thread: 线程的句柄, 每个 pthread 线程都由一个 pthread_t 类型句柄来唯一标识.
addr: 为线程分配的栈内存的基地址.
size: 为线程分配的栈内存的尺寸.
上面说的每一个线程有创建, 运行, 终止, 销毁四个状态, 而 event 则是用来表示线程的四种状态的值, 它的值是如下枚举结构的某一个值:
- enum {
- PTHREAD_INTROSPECTION_THREAD_CREATE = 1, // 创建
- PTHREAD_INTROSPECTION_THREAD_START, // 运行
- PTHREAD_INTROSPECTION_THREAD_TERMINATE, // 终止
- PTHREAD_INTROSPECTION_THREAD_DESTROY, // 销毁
- };
需要注意的是在内省函数中设置回调挂钩函数后只会监控设置之后的所有线程状态的变化. 因此如果我们要监控整个应用生命周期的所有线程的状态时, 需要尽可能早的进行回调函数的设置, 比如可以在某个类的 + load 方法中, 或者在某个全局 C++ 对象的构造函数中设置等等.
回调挂钩函数中的第二个参数 thread 是一个类型为 pthread_t 线程句柄对象, 这个对象的结构并没有对外公开. 但是因为 pthread 库已经被苹果开源: https://opensource.apple.com/source/libpthread/ . 因此我们可以通过线程句柄对象的内部定义来获取关于线程的更多信息. 以方便我们能对线程的各种数据进行更加详细的记录. 当然这里我们需要考虑到线程句柄的不同版本下的数据成员的问题.
最后我们实现一个简单的在 main 函数内实现线程监控的代码示例:
- #include <pthread/introspection.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <stdio.h>
- pthread_introspection_hook_t g_oldpthread_introspection_hook = NULL;
- void mypthread_introspection_hook(unsigned int event, pthread_t thread, void *addr, size_t size)
- {
- __uint64_t threadid;
- pthread_threadid_np(thread, &threadid);
- printf("thread_id = %d, addr = %p, size = %d\n", threadid, addr, size);
- switch (event)
- {
- case PTHREAD_INTROSPECTION_THREAD_CREATE:
- //dothing ..
- break;
- case PTHREAD_INTROSPECTION_THREAD_START:
- //dothing ..
- break;
- case PTHREAD_INTROSPECTION_THREAD_TERMINATE:
- //dothing ..
- break;
- case PTHREAD_INTROSPECTION_THREAD_DESTROY:
- //dothing ..
- break;
- }
- // 记得在最后或者开头调用老的 hook 函数
- if (g_oldpthread_introspection_hook != NULL)
- g_oldpthread_introspection_hook(event, thread, addr, size);
- }
- int main(int argc, char *argv[])
- {
- // 注册线程监控的回调函数为 mypthread_introspection_hook
- g_oldpthread_introspection_hook = pthread_introspection_hook_install(mypthread_introspection_hook);
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- }
- }
你可以通过开源代码中对 pthread_t 类型结构体的定义来获取线程的更多信息, 但是要注意线程库的版本信息.
线程监控回调函数中的代码应该尽可能的精简和高效, 包括官方的头文件中也有一段说明(实际上是可以被 appstore 审核通过的):
This should only be used for introspection and debugging tools. Do not rely
on it in shipping code.
欢迎大家访问欧阳大哥 2013 的 GitHub 地址和简书地址
来源: http://www.jianshu.com/p/813ba526204b