iOS線程生命週期的監控

iOS系統經過Core Services層的Foundation框架提供基於OC語言的NSThread和NSOperationQueue類來實現對線程和線程池的管理和使用。同時也提供了一套基於C語言的GCD線程池函數庫來支持多線程的處理應用。這些高級的線程類或者函數的內部實現大部分最終都會調用POSIX標準中的pthread線程庫中的pthread_xxx系列函數(#include <pthread.h>)來完成線程的建立、運行、暫停、恢復、銷燬、結束等操做。用戶態下的線程建立經過系統調用到達內核態的BSD層並建立bsdthread對象,而BSD層則調用Mach層的ksthread對象來完成最終線程的建立和調度的。 git

線程架構圖

pthread庫中除了提供一系列標準的線程操做API外,還提供了一個用於監控線程建立、運行、結束、銷燬的內省函數(單詞introspection翻譯爲內省,但我以爲叫攔截器可能更好一些)。這個函數定義在頭文件#include <pthread/introspection.h>中,函數的簽名爲:github

pthread_introspection_hook_t pthread_introspection_hook_install(pthread_introspection_hook_t hook)

複製代碼

函數的做用是安裝一個回調函數來掛鉤線程生命週期的四個過程。所以函數的入參是一個函數指針,返回的則是老的掛鉤函數的指針。回調函數是一個格式爲pthread_introspection_hook_t類型的函數,其格式定義以下:bash

typedef void (*pthread_introspection_hook_t)(unsigned int event, pthread_t thread, void *addr, size_t size);

複製代碼

回調函數的每一個參數的意義以下:markdown

event:指定線程所處的狀態。多線程

thread: 線程的句柄,每一個pthread線程都由一個pthread_t類型句柄來惟一標識。架構

addr: 爲線程分配的棧內存的基地址。app

size: 爲線程分配的棧內存的尺寸。框架

上面說的每個線程有建立、運行、終止、銷燬四個狀態,而event則是用來表示線程的四種狀態的值,它的值是以下枚舉結構的某一個值:函數

enum {
	PTHREAD_INTROSPECTION_THREAD_CREATE = 1,  //建立
	PTHREAD_INTROSPECTION_THREAD_START,    //運行
	PTHREAD_INTROSPECTION_THREAD_TERMINATE,  //終止
	PTHREAD_INTROSPECTION_THREAD_DESTROY,  //銷燬
};
複製代碼

須要注意的是在內省函數中設置回調掛鉤函數後只會監控設置以後的全部線程狀態的變化。所以若是咱們要監控整個應用生命週期的全部線程的狀態時,須要儘量早的進行回調函數的設置,好比能夠在某個類的+load方法中,或者在某個全局C++對象的構造函數中設置等等。oop

回調掛鉤函數中的第二個參數thread是一個類型爲pthread_t線程句柄對象,這個對象的結構並無對外公開。可是由於pthread庫已經被蘋果開源:opensource.apple.com/source/libp… 。所以咱們能夠經過線程句柄對象的內部定義來獲取關於線程的更多信息。以方便咱們能對線程的各類數據進行更加詳細的記錄。固然這裏咱們須要考慮到線程句柄的不一樣版本下的數據成員的問題。

最後咱們實現一個簡單的在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地址

相關文章
相關標籤/搜索