linux下的執行緒ID和程序ID
在描述執行緒ID和程序ID之前我們先來分清楚幾個概念:
1. 使用者級執行緒和核心級執行緒
什麼是使用者級執行緒?
使用者級執行緒核心的切換由使用者態程式自己控制核心切換,不需要核心干涉,少了進出核心態的消耗,但不能很好的利用多核Cpu,目前Linux pthread大體是這麼做的。
2. 程序ID,核心執行緒ID,使用者態執行緒ID
程序ID
這裡所說的程序ID指我們通過fork建立子程序,子程序和父程序在核心中獨立執行,並且一個程序對應一個程序描述符(PCB),PCB中包含了程序的ID,通過getpid返回當前程序ID
核心執行緒ID
linux下,核心中,並不存線上程這一說,而是通過複製了程序的PCB作為標識自己(執行緒),作為程序的一個執行分支;既然有程序描述符(PCB)標識,自然就有一個識別符號(ID)來標識著我是你(程序)的哪一個分支,這個識別符號(ID)就是核心中的執行緒ID,通過syscall獲得
使用者態執行緒ID
上面提到使用者級執行緒,對執行緒的操控是由使用者自己來完成,那麼對此執行緒操控,使用者知道你是哪一個執行緒,故此又有了使用者態的執行緒ID;這裡我們通過pthread_self()函式獲得
注:這裡的ID是一個地址,而不是向上面兩個ID是一個整數,下面驗證
3. 執行緒組
什麼是執行緒組?
多執行緒的程序又被稱為執行緒組,執行緒組內的每一個執行緒在核心之中都存在一個程序描述符(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;//標識我是一個執行緒組 ... };
執行緒組ID?
執行緒組的ID和主執行緒ID保持一致
執行緒組的特點?
- 執行緒組內的第一個執行緒,在使用者態被稱為主執行緒(main thread),在核心中被稱為group leader。
- 核心在建立第一個執行緒時,會將執行緒組的ID的值設定為第一個執行緒的執行緒ID,group_leader指標則指向自身,即主執行緒的程序描述符。
- 即執行緒組記憶體在一個執行緒,執行緒ID等於程序ID,該執行緒被稱為主執行緒。
- 在程序中有父程序的概念,但是線上程中所有的執行緒都是對等關係。
下來我們通過例項來看一下執行緒ID和程序ID以及執行緒組
4. 獲取執行緒ID函式
核心級執行緒ID ——syscall()
#include <sys/syscall.h> pid_t tid; tid = syscall(SYS_gettid);
使用者態執行緒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;
}
結果:
程序ID、使用者級執行緒ID、核心級執行緒ID
執行緒組ID