溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于linuxthreads-2.0.1如何分析線程的棧

發(fā)布時間:2021-12-09 09:33:04 來源:億速云 閱讀:136 作者:柒染 欄目:大數(shù)據(jù)

本篇文章為大家展示了基于linuxthreads-2.0.1如何分析線程的棧,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

線程本質上是進程中的一個執(zhí)行流,我們知道,進程有代碼段,線程其實就是進程代碼段中的其中一段代碼。線程的一種實現(xiàn)是作為進程來實現(xiàn)的。通過調用clone,新建一個進程,然后執(zhí)行父進程代碼段里的一個代碼片段。文件、內存等信息都是共享的。因為內存是共享的,所以線程不能共享棧,否則訪問棧的地址的時候,會映射到相同的物理地址,那樣就會互相影響,所以每個線程會有自己獨立的棧。在調用clone函數(shù)的時候會設置棧的范圍。下面通過linuxthreads的代碼看看線程的棧。linuxthreads里有一個__pthread_initialize函數(shù),該函數(shù)會在main函數(shù)執(zhí)行前執(zhí)行。在該函數(shù)中會設置主線程的棧范圍。

   
     
 
    
    

// CURRENT_STACK_FRAME 即sp寄存器。按STACK_SIZE大小對齊
__pthread_initial_thread_bos = (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));              

__pthread_initial_thread_bos 保存主線程的棧頂位置。

然后當我們第一次調用pthread_create創(chuàng)建線程的時候,會調用pthread_initialize_manager函數(shù)初始化manager線程。manager線程是管理其他的線程的線程。

   
     
 
    
    

// 在堆上分配一塊內存用于manager線程的棧,棧頂
 __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE);
// 高地址是棧底
 __pthread_manager_thread_tos = __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE;              

然后調用clone函數(shù)設置manager線程的棧。

   
     
 
    
    __clone(__pthread_manager,__pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]);

最后在函數(shù)pthread_handle_create中設置創(chuàng)建的線程的棧,pthread_handle_create函數(shù)是調用pthread_create函數(shù)的時候被調用的函數(shù)。

   
     
 
    
    

// THREAD_STACK_START_ADDRESS 即__pthread_initial_thread_bos,即主線程的棧頂
#ifndef THREAD_STACK_START_ADDRESS
#define THREAD_STACK_START_ADDRESS  __pthread_initial_thread_bos
#endif
#define THREAD_SEG(seg) ((pthread_t)(THREAD_STACK_START_ADDRESS - (seg) * STACK_SIZE) - 1)
#define SEG_THREAD(thr) (((size_t)THREAD_STACK_START_ADDRESS - (size_t)(thr+1)) / STACK_SIZE)
pthread_t new_thread = THREAD_SEG(sseg);
mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0);              

從上面代碼可知,新建的線程的棧在主線程的棧頂下面(即地址小于主線程的棧頂),創(chuàng)建線程的時候,首先計算新線程的棧地址,然后調用mmap劃出這塊地址。否則訪問的時候會segmentfault。最后調用clone創(chuàng)建進程(線程)并設置棧的棧頂和棧底位置。

   
     
 
    
     __clone(pthread_start_thread, new_thread,(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND| PTHREAD_SIG_RESTART),new_thread);

內存布局如下。

基于linuxthreads-2.0.1如何分析線程的棧

從上面的棧分布我們還可以知道一個信息,即當前執(zhí)行的代碼屬于哪個線程。

   
     
 
    
    

static inline pthread_t thread_self (void)
{
#ifdef THREAD_SELF
 THREAD_SELF
#else
 char *sp = CURRENT_STACK_FRAME;
 // 大于初始化棧則是主線程
 if (sp >= __pthread_initial_thread_bos)
   return &__pthread_initial_thread;
 // 這是manager線程自己申請的空間
 else if (sp >= __pthread_manager_thread_bos
  && sp < __pthread_manager_thread_tos)
   return &__pthread_manager_thread;
 else
   // sp肯定落在某個線程的棧范圍內,STACK_SIZE-1使得低n位全1, 或sp再加1即往高地址,按STACK_SIZE對齊,減去一個pthread_t得到tcb
   return (pthread_t) (((unsigned long int) sp | (STACK_SIZE - 1)) + 1) - 1;
#endif
}              

這就是linuxthreads獲取當前線程的是方法。

上述內容就是基于linuxthreads-2.0.1如何分析線程的棧,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI