1. 程式人生 > >linux中pid,tid, 以及 真實pid的關係

linux中pid,tid, 以及 真實pid的關係

1、pid,tid,真實pid的使用

程序pid: getpid()                 
執行緒tid: pthread_self()     //程序內唯一,但是在不同程序則不唯一。
執行緒pid: syscall(SYS_gettid)     //系統內是唯一的

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>

struct message
{
    int i;
    int j;
};

void *hello(struct
message *str) { printf("child, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS_gettid)); printf("the arg.i is %d, arg.j is %d\n",str->i,str->j); printf("child, getpid()=%d\n",getpid()); while(1); } int main(int argc, char *argv[]) { struct message test; pthread_t thread_id; test.i
=10; test.j=20; pthread_create(&thread_id,NULL,hello,&test); printf("parent, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS_gettid)); printf("parent, getpid()=%d\n",getpid()); pthread_join(thread_id,NULL); return 0; }

getpid()得到的是程序的pid,在核心中,每個執行緒都有自己的PID,要得到執行緒的PID,必須用syscall(SYS_gettid);

pthread_self函式獲取的是執行緒ID,執行緒ID在某程序中是唯一的,在不同的程序中建立的執行緒可能出現ID值相同的情況。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

void *thread_one()
{
    printf("thread_one:int %d main process, the tid=%lu,pid=%ld\n",getpid(),pthread_self(),syscall(SYS_gettid));
}

void *thread_two()
{
    printf("thread two:int %d main process, the tid=%lu,pid=%ld\n",getpid(),pthread_self(),syscall(SYS_gettid));
}

int main(int argc, char *argv[])
{
    pid_t pid;
    pthread_t tid_one,tid_two;
    if((pid=fork())==-1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
        pthread_create(&tid_one,NULL,(void *)thread_one,NULL);
        pthread_join(tid_one,NULL);
    }
    else
    {
        pthread_create(&tid_two,NULL,(void *)thread_two,NULL);
        pthread_join(tid_two,NULL);
    }
    wait(NULL);
    return 0;
}

2、pid與tid的用途

Linux中,每個程序有一個pid,型別pid_t,由getpid()取得。Linux下的POSIX執行緒也有一個id,型別pthread_t,由pthread_self()取得,該id由執行緒維護,其id空間是各個程序獨立的(即不同程序中的執行緒可能有相同的id)。你可能知道,Linux中的POSIX執行緒庫實現的執行緒其實也是一個程序(LWP),只是該程序與主程序(啟動執行緒的程序)共享一些資源而已,比如程式碼段,資料段等。
  有時候我們可能需要知道執行緒的真實pid。比如程序P1要向另外一個程序P2中的某個執行緒傳送訊號時,既不能使用P2的pid,更不能使用執行緒的pthread id,而只能使用該執行緒的真實pid,稱為tid。
  有一個函式gettid()可以得到tid,但glibc並沒有實現該函式,只能通過Linux的系統呼叫syscall來獲取。使用syscall得到tid只需一行程式碼,但為了加深各位看官的印象,簡單提供下面場景。
  有一簇程序,其中一個程序中另外啟了一個執行緒。各程序共享一個數據結構,由shared_ptr指明,其中儲存有執行緒的tid。在各個程序的執行過程中,需要判斷執行緒是否存在,若不存在則(重新)建立。
  首先,線上程函式的開始,需要將自己的tid儲存至共享記憶體,

點選(此處)摺疊或開啟

  1. #include <sys/syscall.h>
  2. #include <sys/types.h>
  3. void*
  4. thread_func(void *args)
  5. {
  6.     //~ lock shared memory
  7.     shared_ptr->tid = syscall(SYS_gettid); //~ gettid()
  8.     //~ unlock shared memory
  9.     //~ other stuff
  10. }
  在各程序中判斷程序是否存在,

點選(此處)摺疊或開啟

  1. //~ lock shared memory
  2. pthread_t id;
  3. if (shared_ptr->tid == 0) { //~ tid is initialized to 0
  4.     pthread_create(&id, NULL, thread_func, NULL);
  5. } else if (shared_ptr->tid > 0) {
  6.     int ret = kill(shared_ptr->tid, 0); //~ send signal 0 to thread
  7.     if (ret != 0) { //~ thread already died
  8.         pthread_create(&id, NULL, thread_func, NULL);
  9.     }
  10. }
  11. //~ unlock shared memory

3、linux 系統中檢視pid,tid的方法

  • 樓上說的linux執行緒和程序是一樣的,這個說法是錯誤的。

  • 看了樓主的問題,感覺樓主是被PID給弄混了,執行緒程序都會有自己的ID,這個ID就叫做PID,PID是不特指程序ID,執行緒ID也可以叫做PID。


引用原文

The four threads will have the same PID but only when viewed from above. What you (as a user) call a PID is not what the kernel (looking from below) calls a PID.

In the kernel, each thread has it's own ID, called a PID (although it would possibly make more sense to call this a TID, or thread ID) and they also have a TGID (thread group ID) which is the PID of the thread that started the whole process.

Simplistically, when a new process is created, it appears as a thread where both the PID and TGID are the same (new) number.

When a thread starts another thread, that started thread gets its own PID (so the scheduler can schedule it independently) but it inherits the TGID from the original thread.

That way, the kernel can happily schedule threads independent of what process they belong to, while processes (thread group IDs) are reported to you.

關於執行緒繼承關係圖如下:

               USER VIEW
 <-- PID 43 --> <----------------- PID 42 ----------------->
                     +---------+
                     | process |
                    _| pid=42  |_
                  _/ | tgid=42 | \_ (new thread) _
       _ (fork) _/   +---------+                  \
      /                                        +---------+
+---------+                                    | process |
| process |                                    | pid=44  |
| pid=43  |                                    | tgid=42 |
| tgid=43 |                                    +---------+
+---------+
 <-- PID 43 --> <--------- PID 42 --------> <--- PID 44 --->
                     KERNEL VIEW

在這裡你可以清晰的看到,建立一個新的程序會給一個新的PID和TGID,並且2個值相同,
當建立一個新的執行緒的時候,會給你一個新的PID,並且TGID和之前開始的程序一致。

  • 樓主按下H,切換到程序檢視,會發現只剩下一個了

建議建議樓主不要被名字PID給迷惑,一個東西在不同視角是不一樣的。

建議樓主用HTOP,清晰方便,高效,還帶命令列顯示圖。

另外附上

Linux通過程序檢視執行緒的方法 1).htop按t(顯示程序執行緒巢狀關係)和H(顯示執行緒) ,然後F4過濾程序名。2).ps -eLf | grep java(快照,帶執行緒命令,e是顯示全部程序,L是顯示執行緒,f全格式輸出) 3).pstree -p <pid>(顯示程序樹,不加pid顯示所有) 4).top -Hp <pid> (實時) 5).ps -T -p <pid>(快照)推薦程度按數字從小到大。