標籤:libc 資料區段 else inherits 有一個 技術分享 ace def 方法
對於ubuntu14.04作業系統,可以在/usr/src/linux-headers-4.4.0-31/include/linux/sched.h檔案中看到進程式控制制塊的結構體,如下
struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; atomic_t usage; unsigned int flags; /* per process flags, defined below */ unsigned int ptrace;#ifdef CONFIG_SMP struct llist_node wake_entry; int on_cpu; unsigned int wakee_flips; unsigned long wakee_flip_decay_ts; struct task_struct *last_wakee; int wake_cpu;#endif ...... ...... pid_t pid; pid_t tgid; ...... ......}
可以看到,裡面定義了兩個欄位,pid和tgid,其中pid就是這個輕量級進程lwp的id,而tgid是lwp組的id,即主lwp的id
原文:http://blog.csdn.net/u012398613/article/details/52183708
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儲存至共用記憶體,
點擊(此處)摺疊或開啟
- #include <sys/syscall.h>
- #include <sys/types.h>
- void*
- thread_func(void *args)
- {
- //~ lock shared memory
- shared_ptr->tid = syscall(SYS_gettid); //~ gettid()
- //~ unlock shared memory
- //~ other stuff
- }
在各進程中判斷進程是否存在,
點擊(此處)摺疊或開啟
- //~ lock shared memory
- pthread_t id;
- if (shared_ptr->tid == 0) { //~ tid is initialized to 0
- pthread_create(&id, NULL, thread_func, NULL);
- } else if (shared_ptr->tid > 0) {
- int ret = kill(shared_ptr->tid, 0); //~ send signal 0 to thread
- if (ret != 0) { //~ thread already died
- pthread_create(&id, NULL, thread_func, NULL);
- }
- }
- //~ unlock shared memory
3、linux 系統中查看pid,tid的方法
線程進程都會有自己的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和之前開始的進程一致。
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>
(快照)推薦程度按數字從小到大。
C語言編程中pid, tid以及真實pid的關係