中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

基于linuxthreads2.0.1線程源碼如何分析線程庫的初始化和線程的管理

發布時間:2021-12-09 09:36:21 來源:億速云 閱讀:127 作者:柒染 欄目:大數據

今天就跟大家聊聊有關基于linuxthreads2.0.1線程源碼如何分析線程庫的初始化和線程的管理,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

初步分析一下線程的初始化和管理。

線程庫的初始化代碼如下。

   
     
 
    
    


// 在main函數之前執行該函數
void __pthread_initialize(void) __attribute__((constructor));

void __pthread_initialize(void)
{
 struct sigaction sa;
 sigset_t mask;

 /* We may be called by others.  This may happen if the constructors
    are not called in the order we need.  */
 if (__pthread_initial_thread_bos != NULL)
   return;

 /* For the initial stack, reserve at least STACK_SIZE bytes of stack
    below the current stack address, and align that on a
    STACK_SIZE boundary. */
 __pthread_initial_thread_bos =
   // 按STACK_SIZE大小對齊
   (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
 /* Update the descriptor for the initial thread. */
 // 即main函數代表的主進程id
 __pthread_initial_thread.p_pid = getpid();
 /* If we have special thread_self processing, initialize that for the
    main thread now.  */
#ifdef INIT_THREAD_SELF
 INIT_THREAD_SELF(&__pthread_initial_thread);
#endif
 /* Setup signal handlers for the initial thread.
    Since signal handlers are shared between threads, these settings
    will be inherited by all other threads. */
 // 為兩個信號注冊處理函數
 sa.sa_handler = __pthread_sighandler;
 sigemptyset(&sa.sa_mask);
 sa.sa_flags = SA_RESTART; /* does not matter for regular threads, but
                              better for the thread manager */
 sigaction(PTHREAD_SIG_RESTART, &sa, NULL);
 sa.sa_handler = pthread_handle_sigcancel;
 sa.sa_flags = 0;
 sigaction(PTHREAD_SIG_CANCEL, &sa, NULL);

 /* Initially, block PTHREAD_SIG_RESTART. Will be unblocked on demand. */
 // 屏蔽restart信號
 sigemptyset(&mask);
 sigaddset(&mask, PTHREAD_SIG_RESTART);
 sigprocmask(SIG_BLOCK, &mask, NULL);
 /* Register an exit function to kill all other threads. */
 /* Do it early so that user-registered atexit functions are called
    before pthread_exit_process. */
 // 注冊退出時執行的函數
 __on_exit(pthread_exit_process, NULL);
}              

在執行main函數之前會先執行__pthread_initialize函數,該函數做的事情主要有

1 在棧上分配一塊內存。

2 保存當前進程,進main函數對應的進程的pid。

3 注冊兩個信號處理函數。

4 注冊退出時執行的函數

接下來我們會調用pthread_create進行線程的創建。我們來看看該函數做了什么。

   
     
 
    
    

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                  void * (*start_routine)(void *), void *arg)
{
 pthread_t self = thread_self();
 struct pthread_request request;
 // 還沒執行過pthread_initialize_manager則執行,用于初始化manager線程
 if (__pthread_manager_request < 0) {
   if (pthread_initialize_manager() < 0) return EAGAIN;
 }
 // 給manager發一下請求
 request.req_thread = self;
 request.req_kind = REQ_CREATE;
 request.req_args.create.attr = attr;
 request.req_args.create.fn = start_routine;
 request.req_args.create.arg = arg;
 // 獲取當前線程的信號掩碼
 sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
             &request.req_args.create.mask);
 // 通過管道寫入,通知manager線程,新建一個線程
 __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
 // 掛起,等待manager喚醒
 suspend(self);
 // 等于0說明創建成功,否則返回失敗的錯誤碼,p_retval在pthread_handle_create中設置
 if (self->p_retcode == 0) *thread = (pthread_t) self->p_retval;
 return self->p_retcode;
}              

我們發現,該函數沒有做實際的事情,他通過往管道寫了一些數據。這時候就要先看pthread_initialize_manager函數了。

   
     
 
    
    

static int pthread_initialize_manager(void)
{
 int manager_pipe[2];

 /* Setup stack for thread manager */
 // 在堆上分配一塊內存用于manager線程的棧
 __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE);
 if (__pthread_manager_thread_bos == NULL) return -1;
 // limit
 __pthread_manager_thread_tos =
   __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE;
 /* Setup pipe to communicate with thread manager */
 if (pipe(manager_pipe) == -1) {
   free(__pthread_manager_thread_bos);
   return -1;
 }
 __pthread_manager_request = manager_pipe[1]; /* writing end */
 __pthread_manager_reader = manager_pipe[0]; /* reading end */
 /* Start the thread manager */
 // 新建一個manager線程,manager_pipe是__thread_manager函數的入參
 if (__clone(__pthread_manager,
 __pthread_manager_thread_tos,
 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
 (void *)(long)manager_pipe[0]) == -1) {
   free(__pthread_manager_thread_bos);
   __libc_close(manager_pipe[0]);
   __libc_close(manager_pipe[1]);
   __pthread_manager_request = -1;
   return -1;
 }
 return 0;
}              

該函數做了幾件事情

1 在堆上申請一塊內存用作manager線程的棧

2 創建了一個管道,用于manager線程和其他線程通信。

3 然后新建了一個進程,然后執行__pthread_manager函數。(具體可參考http://www.man7.org/linux/man-pages/man2/clone.2.html)

manager線程是linuxthreads線程庫比較重要的存在,他是管理其他線程的線程。我們接著看_pthread_manager函數的代碼。

   
     
 
    
    

/* The server thread managing requests for thread creation and termination */

int __pthread_manager(void *arg)
{
 // 管道的讀端
 int reqfd = (long)arg;
 sigset_t mask;
 fd_set readfds;
 struct timeval timeout;
 int n;
 struct pthread_request request;

 /* If we have special thread_self processing, initialize it.  */
#ifdef INIT_THREAD_SELF
 INIT_THREAD_SELF(&__pthread_manager_thread);
#endif
 /* Block all signals except PTHREAD_SIG_RESTART */
 // 初始化為全1
 sigfillset(&mask);
 // 設置某一位為0,這里設置可以處理restart信號
 sigdelset(&mask, PTHREAD_SIG_RESTART);
 // 設置進程的信號掩碼
 sigprocmask(SIG_SETMASK, &mask, NULL);
 /* Enter server loop */
 while(1) {
   // 清0
   FD_ZERO(&readfds);
   // 置某位為1,位數由reqfd算得,這里是管道讀端的文件描述符
   FD_SET(reqfd, &readfds);
   // 阻塞的超時時間
   timeout.tv_sec = 2;
   timeout.tv_usec = 0;
   // 定時阻塞等待管道有數據可讀
   n = __select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
   /* Check for termination of the main thread */
   // 父進程id為1說明主進程(線程)已經退出,子進程被init(pid=1)進程接管了,
   if (getppid() == 1) {
     // 0說明不需要給主線程發,因為他已經退出了
     pthread_kill_all_threads(SIGKILL, 0);
     return 0;
   }
   /* Check for dead children */
   if (terminated_children) {
     terminated_children = 0;
     pthread_reap_children();
   }
   /* Read and execute request */
   // 管道有數據可讀
   if (n == 1 && FD_ISSET(reqfd, &readfds)) {
     // 讀出來放到request
     n = __libc_read(reqfd, (char *)&request, sizeof(request));
     ASSERT(n == sizeof(request));
     switch(request.req_kind) {
     // 創建線程
     case REQ_CREATE:
       request.req_thread->p_retcode =
         pthread_handle_create((pthread_t *) &request.req_thread->p_retval,
                               request.req_args.create.attr,
                               request.req_args.create.fn,
                               request.req_args.create.arg,
                               request.req_args.create.mask,
                               request.req_thread->p_pid);
       // 喚醒父線程
       restart(request.req_thread);
       break;
     case REQ_FREE:
       pthread_handle_free(request.req_args.free.thread);
       break;
     case REQ_PROCESS_EXIT:
       pthread_handle_exit(request.req_thread,
                           request.req_args.exit.code);
       break;
     case REQ_MAIN_THREAD_EXIT:
       // 標記主線程退出
       main_thread_exiting = 1;
       // 其他線程已經退出了,只有主線程了,喚醒主線程,主線程也退出,見pthread_exit,如果還有子線程沒退出則主線程不能退出
       if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
         restart(__pthread_main_thread);
         return 0;
       }
       break;
     }
   }
 }
}              

該函數是manager線程的主要代碼。他類似一個服務器一起。接收其他線程發過來的信息,然后處理。在switch那里可以看到具體的處理。這里我們只看線程創建的邏輯。函數是pthread_handle_create。

   
     
 
    
    

// pthread_create發送信號給manager,manager調該函數創建線程
static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
                                void * (*start_routine)(void *), void *arg,
                                sigset_t mask, int father_pid)
{
 int sseg;
 int pid;
 pthread_t new_thread;
 int i;

 /* Find a free stack segment for the current stack */
 sseg = 0;
 while (1) {
   while (1) {
     if (sseg >= num_stack_segments) {
       if (pthread_grow_stack_segments() == -1) return EAGAIN;
     }
     if (stack_segments[sseg] == 0) break;
     sseg++;
   }
   // 標記已使用
   stack_segments[sseg] = 1;
   // 存儲線程元數據的地方
   new_thread = THREAD_SEG(sseg);
   /* Allocate space for stack and thread descriptor. */
   // 給線程分配棧
   if (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)
       != (caddr_t) -1) break;
   /* It seems part of this segment is already mapped. Leave it marked
      as reserved (to speed up future scans) and try the next. */
   sseg++;
 }
 /* Initialize the thread descriptor */
 new_thread->p_nextwaiting = NULL;
 new_thread->p_spinlock = 0;
 new_thread->p_signal = 0;
 new_thread->p_signal_jmp = NULL;
 new_thread->p_cancel_jmp = NULL;
 new_thread->p_terminated = 0;
 new_thread->p_detached = attr == NULL ? 0 : attr->detachstate;
 new_thread->p_exited = 0;
 new_thread->p_retval = NULL;
 new_thread->p_joining = NULL;
 new_thread->p_cleanup = NULL;
 new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE;
 new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED;
 new_thread->p_canceled = 0;
 new_thread->p_errno = 0;
 new_thread->p_h_errno = 0;
 new_thread->p_initial_fn = start_routine;
 new_thread->p_initial_fn_arg = arg;
 new_thread->p_initial_mask = mask;
 for (i = 0; i < PTHREAD_KEYS_MAX; i++) new_thread->p_specific[i] = NULL;
 /* Do the cloning */
 pid = __clone(pthread_start_thread, new_thread,
(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
| PTHREAD_SIG_RESTART),
new_thread);
 /* Check if cloning succeeded */
 if (pid == -1) {
   /* Free the stack */
   munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
  INITIAL_STACK_SIZE);
   stack_segments[sseg] = 0;
   return EAGAIN;
 }
 /* Set the priority and policy for the new thread, if available. */
 if (attr != NULL && attr->schedpolicy != SCHED_OTHER) {
   switch(attr->inheritsched) {
   case PTHREAD_EXPLICIT_SCHED:
     sched_setscheduler(pid, attr->schedpolicy, &attr->schedparam);
     break;
   case PTHREAD_INHERIT_SCHED:
     { struct sched_param father_param;
       int father_policy;
       father_policy = sched_getscheduler(father_pid);
       sched_getparam(father_pid, &father_param);
       sched_setscheduler(pid, father_policy, &father_param);
     }
     break;
   }
 }
 /* Insert new thread in doubly linked list of active threads */
 // 頭插法,插入主線程和其他線程之間,
 new_thread->p_prevlive = __pthread_main_thread;
 new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
 __pthread_main_thread->p_nextlive->p_prevlive = new_thread;
 __pthread_main_thread->p_nextlive = new_thread;
 /* Set pid field of the new thread, in case we get there before the
    child starts. */
 new_thread->p_pid = pid;
 /* We're all set */
 *thread = new_thread;
 return 0;
}

             

該函數分配一個tcb結構體表示新的線程。然后分配一個線程棧,調用clone新建一個進程。最后鏈接到線程鏈表中。最后執行pthread_start_thread函數。該函數代碼如下。

   
     
 
    
    

// 傳給clone函數的參數
static int pthread_start_thread(void *arg)
{
 // 新建的線程
 pthread_t self = (pthread_t) arg;
 void * outcome;
 /* Initialize special thread_self processing, if any.  */
#ifdef INIT_THREAD_SELF
 INIT_THREAD_SELF(self);
#endif
 /* Make sure our pid field is initialized, just in case we get there
    before our father has initialized it. */
 // 記錄線程對應進程的id
 self->p_pid = getpid();
 /* Initial signal mask is that of the creating thread. (Otherwise,
    we'd just inherit the mask of the thread manager.) */
 // 設置線程的信號掩碼,值繼承于父線程
 sigprocmask(SIG_SETMASK, &self->p_initial_mask, NULL);
 /* Run the thread code */
 // 開始執行線程的主函數
 outcome = self->p_initial_fn(self->p_initial_fn_arg);
 /* Exit with the given return value */
 // 執行完退出
 pthread_exit(outcome);
 return 0;
}              

沒有太多邏輯,執行用戶傳進來的函數。執行完后退出。

看完上述內容,你們對基于linuxthreads2.0.1線程源碼如何分析線程庫的初始化和線程的管理有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

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

AI

公安县| 丹江口市| 健康| 吉林市| 汉川市| 托克托县| 乳山市| 固阳县| 若羌县| 景洪市| 丹阳市| 迁安市| 岗巴县| 馆陶县| 鄢陵县| 新竹市| 淮安市| 宽城| 金门县| 雅安市| 新河县| 牡丹江市| 通江县| 贺兰县| 天柱县| 津南区| 阿巴嘎旗| 奉贤区| 霍州市| 隆化县| 东乌| 保亭| 祁东县| 金平| 韶关市| 德州市| 承德县| 万山特区| 望城县| 西平县| 万荣县|