在linux中,线程与进程最大的区别就是是否共享同一块地址空间,而且共享同一块地址空间的那一组线程将显现相同的PID号。
       在实际编程应用中,我们会很容易发现并证明,一组同源线程的PID都是一样的,但它们的PID真的一样么?
       在linux中,线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源:

1. clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

       上面的代码产生的结果和调用fork()差不多,只是父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序。换个说法就是, 新建的进程和它的父进程就是流行的所谓线程 。  


       对比一下,一个普通的fork()的实现是:

1. clone(SIGCHLD, 0);


      而vfork()的实现是:

1. clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);


      传递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类。下面列举部分clone()参数标志,这些是在中定义的。


       CLONE_FILES     父子进程共享打开的文件


       CLONE_FS    父子进程共享文件系统信息


       CLONE_SIGHAND      父子进程共享信号处理函数


       CLONE_VM     父子进程共享地址空间


       CLONE_VFORK    调用vfork(),所以父进程准备睡眠等待子进程将其唤醒



下面用一段程序测试一下,代码如下:


这段测试程序是主线程创建10个线程,并分别打印PID及TID。

1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <pthread.h>
4. #include <unistd.h>
5. #include <sys/types.h>
6. #include <string.h>
7.  
8. pthread_t tid[10];
9.  
10. void * thread_handler(void *arg)
11. {
12. printf("tid%d:%u,pid:%u\n", (int)arg, (unsigned)pthread_self(), 
13. (unsigned)getpid());
14. while(1){
15. sleep(1);
16. }
17. return NULL;
18. }
19.  
20. int main(void)
21. {
22. int i, ret;
23. pid_t pid;
24. printf("main tid:%u,pid:%u\n", (unsigned)pthread_self(),
25. (unsigned)getpid());
26. for(i = 0; i < 10; i++){
27. if((ret = pthread_create(&tid[i], NULL, thread_handler, 
28. (void *)i)) != 0){
29. fprintf(stderr, "pthread_create:%s\n",
30. strerror(ret));
31. exit(1);
32. }
33. }
34. sleep(3);
35. = fork();
36. if(pid == 0){
37. printf("son tid:%u,pid:%u\n", (unsigned)pthread_self(),
38. (unsigned)getpid());
39. while(1);
40. sleep(1);
41. }
42. while(1)
43. sleep(2);
44. exit(0);
45. }

编译运行:


  1. zx@zhangxu:~/lianxi/apue$ gcc -o test pthreadid.c -lpthread
  2. @zhangxu:~/lianxi/apue$ ./test
  3. 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都相同。



1. ├─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的值都是连续的。

 

参考资料:《linux内核设计与实现》