1. 程式人生 > >linux下的執行緒ID和程序ID

linux下的執行緒ID和程序ID

 在描述執行緒ID和程序ID之前我們先來分清楚幾個概念:

1. 使用者級執行緒和核心級執行緒

  1. 什麼是使用者級執行緒?

    使用者級執行緒核心的切換由使用者態程式自己控制核心切換,不需要核心干涉,少了進出核心態的消耗,但不能很好的利用多核Cpu,目前Linux pthread大體是這麼做的。

2. 程序ID,核心執行緒ID,使用者態執行緒ID

  1. 程序ID

    這裡所說的程序ID指我們通過fork建立子程序,子程序和父程序在核心中獨立執行,並且一個程序對應一個程序描述符(PCB),PCB中包含了程序的ID,通過getpid返回當前程序ID

  2. 核心執行緒ID

    linux下,核心中,並不存線上程這一說,而是通過複製了程序的PCB作為標識自己(執行緒),作為程序的一個執行分支;既然有程序描述符(PCB)標識,自然就有一個識別符號(ID)來標識著我是你(程序)的哪一個分支,這個識別符號(ID)就是核心中的執行緒ID,通過syscall獲得

  3. 使用者態執行緒ID

    上面提到使用者級執行緒,對執行緒的操控是由使用者自己來完成,那麼對此執行緒操控,使用者知道你是哪一個執行緒,故此又有了使用者態的執行緒ID;這裡我們通過pthread_self()函式獲得
    注:這裡的ID是一個地址,而不是向上面兩個ID是一個整數,下面驗證

3. 執行緒組

  1. 什麼是執行緒組?

    多執行緒的程序又被稱為執行緒組,執行緒組內的每一個執行緒在核心之中都存在一個程序描述符(task_struct)與之對應。
    個人理解:其實就是擁有多個執行緒的程序的描述符,一個結構體,裡面存放著自己的一些資訊,並且還有標識自己是這些多執行緒的領頭的資訊

    struct task_struct{
    ...
    pid_t pid;//核心級執行緒id,(個人猜測:核心看到他是一個程序,所以為pid)
    pid_t tgid;//使用者級程序id,(個人猜測:使用者看到他是一個執行緒,所以為tgid)
    ...
    struct task_struct *group_leader;//執行緒組指標,指標指向自己,表示是主執行緒
    ...
    struct list_head thread_group;//標識我是一個執行緒組
    ...
    };
  2. 執行緒組ID?

    執行緒組的ID和主執行緒ID保持一致

  3. 執行緒組的特點?

    1. 執行緒組內的第一個執行緒,在使用者態被稱為主執行緒(main thread),在核心中被稱為group leader。
    2. 核心在建立第一個執行緒時,會將執行緒組的ID的值設定為第一個執行緒的執行緒ID,group_leader指標則指向自身,即主執行緒的程序描述符。
    3. 即執行緒組記憶體在一個執行緒,執行緒ID等於程序ID,該執行緒被稱為主執行緒。
    4. 在程序中有父程序的概念,但是線上程中所有的執行緒都是對等關係。

下來我們通過例項來看一下執行緒ID和程序ID以及執行緒組

4. 獲取執行緒ID函式

  1. 核心級執行緒ID ——syscall()

    
    #include <sys/syscall.h>
    
    pid_t tid;
    tid = syscall(SYS_gettid);
  2. 使用者態執行緒ID ——-pthread_self() 

        #include <pthread.h>
        pthread_t pthread_self(void);
        返回值:成功返回0,失敗返回錯誤碼

例項:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
void* thread_run(void* arg)
{
    (void)arg;
    pid_t pid = syscall(SYS_gettid);

    while(1){
        printf("I am thread->程序ID:%d ->核心執行緒ID:%d ->使用者態執行緒ID:%lx\n",getpid(),pid,pthread_self());
        sleep(1);
    }

}
int main()
{
    pid_t pid = syscall(SYS_gettid);//獲取核心中的執行緒ID

    int ret;
    pthread_t tid;

    ret = pthread_create(&tid,NULL,thread_run,NULL);
    if(ret != 0){
        perror("pthread_create");
        exit(1);
    }

    while(1){
        printf("I am main  ->程序ID:%d ->核心執行緒ID:%d ->使用者態執行緒ID:%lx\n",getpid(),pid,pthread_self());
        sleep(1);
    }

    return 0;
}

結果:

  1. 程序ID、使用者級執行緒ID、核心級執行緒ID

    這裡寫圖片描述

  2. 執行緒組ID

    這裡寫圖片描述