add by zhj: 下面是我對pid,tgid,ppid的個人理解
對於ubuntu14.04操作系統,可以在/usr/src/linux-headers-4.4.0-31/include/linux/sched.h文件中看到進程控制塊的結構體,如下
structtask_struct {volatile long state; /*-1 unrunnable, 0 runnable, >0 stopped*/
void *stack;
atomic_t usage;
unsignedint flags; /*per process flags, defined below*/unsignedintptrace;
#ifdef CONFIG_SMPstructllist_node wake_entry;inton_cpu;
unsignedintwakee_flips;
unsignedlongwakee_flip_decay_ts;struct task_struct *last_wakee;intwake_cpu;#endif......
......
pid_t pid;
pid_t tgid;
......
......
}
可以看到,里面定義了兩個字段,pid和tgid,其中pid就是這個輕量級進程lwp的id,而tgid是輕量級進程組的id,當創建進程時,我們可以為自己指定
進程的tgid字段,貌似可以隨便指定,只要存在就行,另外在父進程中,可以為子進程設置進程組id,如果沒有指定,它會繼承父進程的進程組id。
還有一個概念ppid,我沒在這個結構體中找到,但操作系統肯定是會記錄的,在Python中,通過os.get_ppid()就可以獲取當前進程的父進程。tgid與ppid,
這兩者其實沒有任何關系,因為tgid是可以自己來指定的,平時基本不用,不用管它。
1、pid,tid,真實pid的使用
進程pid: getpid() // 相當於os.getpid()
線程tid: pthread_self()//進程內唯一,但是在不同進程則不唯一。相當於thread.get_ident()
線程pid: syscall(SYS_gettid) //系統內是唯一的。python中沒有現成的方法,需要手動調用動態鏈接庫ctypes.CDLL('libc.so.6').syscall(xx)
#include#include#include#include
structmessage
{inti;intj;
};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[])
{structmessage 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 #include#include#include#include
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
#include
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