Linux线程ID和进程ID
2014-07-30 15:54
337 查看
1. Linux线程的线程ID和进程ID
Linux内核并不支持真正意义上的线程,Linux线程库是用与普通进程具有同样内核调度视图的轻量级进程来实现线程支持的。这些轻量级进程拥有独立的进程id,在进程调度、信号处理、IO等方面享有与普通进程一样的能力。每个Linux线程都同时具有线程id和进程id,其中进程id就是内核所维护的进程号,而线程id则由线程库分配和维护。
1)每个进程都有自己的PID,这是唯一的。
2)除此之外,每个进程还有其它的ID标识,比如处于某个线程组中的所有进程都有一个统一的线程组ID(TGID),如果进程没有使用线程,PID和TGID是相同的,其实主线程的PID和TGID就是相同的。
3)独立进程可以合并成为进程组。
4)几个进程组可以合并成一个会话,会话中的所有进程都有同样的会话ID。
重点关注一下 task_struct 中与进程ID相关的两个成员:
struct task_struct{ pid_t pid; pid_t tgid; }属于同一个进程的所有线程,tgid是相同的,都指向线程组第一个进程(主线程)的PID值。
可以分别通过getpid(), syscall(SYS_gettid)获取对应的值。结合下面第2部分的程序,能够更直观地看出getpid()获取tgid、syscall()获取PID。
因此,对于Linux而言,所谓线程组共享进程ID,其实是通过 tgid 表示的,而线程组中的每个线程本质上是有自己的进程ID号的。
2. 通过程序查看线程相关的ID
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <linux/unistd.h> pid_t gettid() { return syscall(__NR_gettid); } static void *phandle(void *arg) { pid_t pid_chld, pid_chld1; pthread_t tid; pid_chld = getpid(); pid_chld1 = gettid(); tid = pthread_self(); printf("<child pthread>@(pid=%d/ptid=%d/tid=%lu) Child pthread ready to sleep 5 \r\n", pid_chld, pid_chld1,tid); sleep(2); printf("<child pthread>@(pid=%d/ptid=%d/tid=%lu) Child pthread exit\r\n", pid_chld, pid_chld1,tid); return NULL; } int main(int argc, char *argv[]) { int cnt; pid_t pid; pthread_t g_tid,tid; pid = getpid(); g_tid = pthread_self(); printf("[[main pthread]] (pid=%lu/tid_mian=%lu) start! \r\n", pid, g_tid); for(cnt=0; cnt<2; cnt++) { pthread_create(&tid,NULL,phandle,NULL); printf("[[main pthread]] create a child pthread_%d(%lu)\r\n",cnt,tid); } sleep(5); printf("[[main pthread]] (pid=%lu/tid_mian=%lu) exit!\r\n", pid, g_tid); exit(0); }
执行结果如下:
# gcc -o pid pthread_pid_tid.c -lpthread
# ./pid
[[main pthread]] (pid=3221/tid_mian=3076355776) start!
[[main pthread]] create a child pthread_0(3076352832)
[[main pthread]] create a child pthread_1(3067960128)
<child pthread>@(pid=3221/ptid=3223/tid=3067960128) Child pthread ready to sleep 5
<child pthread>@(pid=3221/ptid=3222/tid=3076352832) Child pthread ready to sleep 5
<child pthread>@(pid=3221/ptid=3223/tid=3067960128) Child pthread exit
<child pthread>@(pid=3221/ptid=3222/tid=3076352832) Child pthread exit
[[main pthread]] (pid=3221/tid_mian=3076355776) exit!
3. 转载网上的一篇关于线程ID和进程ID的文章
原文:http://blog.chinaunix.net/uid-24567872-id-100482.html 点击打开链接在linux中,线程与进程最大的区别就是是否共享同一块地址空间,而且共享同一块地址空间的那一组线程将显现相同的PID号。
在实际编程应用中,我们会很容易发现并证明,一组同源线程的PID都是一样的,但它们的PID真的一样么?
在linux中,线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
上面的代码产生的结果和调用fork()差不多,只是父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序。换个说法就是,新建的进程和它的父进程就是流行的所谓线程。
对比一下,一个普通的fork()的实现是:
clone(SIGCHLD, 0);
而vfork()的实现是:
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);
传递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类。下面列举部分clone()参数标志,这些是在<linux/sched.h>中定义的。
CLONE_FILES 父子进程共享打开的文件
CLONE_FS 父子进程共享文件系统信息
CLONE_SIGHAND 父子进程共享信号处理函数
CLONE_VM 父子进程共享地址空间
CLONE_VFORK 调用vfork(),所以父进程准备睡眠等待子进程将其唤醒
下面用一段程序测试一下,代码如下:
这段测试程序是主线程创建10个线程,并分别打印PID及TID。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
pthread_t tid[10];
void * thread_handler(void *arg)
{
printf("tid%d:%u,pid:%u\n", (int)arg, (unsigned)pthread_self(),
(unsigned)getpid());
while(1){
sleep(1);
}
return NULL;
}
int main(void)
{
int i, ret;
pid_t pid;
printf("main tid:%u,pid:%u\n", (unsigned)pthread_self(),
(unsigned)getpid());
for(i = 0; i < 10; i++){
if((ret = pthread_create(&tid[i], NULL, thread_handler,
(void *)i)) != 0){
fprintf(stderr, "pthread_create:%s\n",
strerror(ret));
exit(1);
}
}
sleep(3);
pid = fork();
if(pid == 0){
printf("son tid:%u,pid:%u\n", (unsigned)pthread_self(),
(unsigned)getpid());
while(1);
sleep(1);
}
while(1)
sleep(2);
exit(0);
}
编译运行:
zx@zhangxu:~/lianxi/apue$ gcc -o
test pthreadid.c -lpthread
zx@zhangxu:~/lianxi/apue$ ./test
main tid:3077888816,pid:2418
tid0:3077880688,pid:2418
tid1:3069487984,pid:2418
tid2:3061095280,pid:2418
tid3:3052702576,pid:2418
tid4:3044309872,pid:2418
tid5:3035917168,pid:2418
tid6:3027524464,pid:2418
tid7:3019131760,pid:2418
tid8:3010739056,pid:2418
tid9:3002346352,pid:2418
son tid:3077888816,pid:2429
从结果可以看出,测试程序中所有线程的PID都相同。
在另一个终端调用pstree -pu
├─gnome-terminal(1624,zx)─┬─bash(1628)
│ ├─bash(1704)───pstree(2430)
│ ├─bash(1927)───test(2418)─┬─test(2429)
│ │ ├─{test}(2419)
│ │ ├─{test}(2420)
│ │ ├─{test}(2421)
│ │ ├─{test}(2422)
│ │ ├─{test}(2423)
│ │ ├─{test}(2424)
│ │ ├─{test}(2425)
│ │ ├─{test}(2426)
│ │ ├─{test}(2427)
│ │ └─{test}(2428)
从中可以看出,每个线程的PID其实是不同的,因为测试程序是理想状态,只有一个主线程在创建线程,所以PID的值都是连续的。
相关文章推荐
- C/C++ 获取Linux线程ID与进程ID
- linux查看某个进程的线程id(spid)
- linux线程的线程ID与其进程ID
- linux下多线程学习4_打印线程id和进程id
- linux 线程id 与进程id对应关系
- linux线程的线程ID与其进程ID
- linux 线程ID与进程ID 初探
- 从内核实现看Linux进程与线程
- linux线程,进程经典文章
- linux线程,进程经典文章
- linux 线程 进程经典文章
- 将 Win32 C/C++ 应用程序迁移到 POWER 上的 Linux,第 1 部分: 进程、线程和共享内存服务 (转)
- 通过进程ID查看进程信息,调出进程线程集合,查看进程模块,并对其进行操作!
- Linux 进程和线程查看以及管理
- Linux 进程管理--------------------线程
- linux进程的用户ID,有效ID,保存的设置ID
- [Pthread] Linux上获得线程Id的方法
- linux线程,进程经典文章
- linux下查看进程/线程
- 将 Windows IPC 应用程序移植到 Linux,第 1 部分: 进程和线程