进程与线程

来源:互联网 发布:字幕编辑软件 编辑:程序博客网 时间:2024/05/18 03:12

【描述】线程和进程是一个老生常谈的话题,线程和进程的区别和优缺点有哪些?线程最多可以开多少个?

【解析】

1 区别

 线程是CPU调度的最小单位,进程是资源分配的最小单位。进程是线程的容器,真正完成代码执行的是线程,而进程则作为线程的执行环境。在32位的Windows操作系统中,系统要为每一个进程分配私有的232=4GB的虚拟地址空间。但实际上只有2GB的空间被用户分区使用,另外2GB空间被用于内核代码、设备驱动程序等内核分区。在进程中,线程共享用户分区这一地址空间。

2 优缺点

在Windows系统中,对于多进程程序而言,系统要为进程分配私有的4GB虚拟地址空间,占用的资源较多。而对于多线程的程序,多线程共享同一进程的地址空间,因此占用的资源较少。当进程切换时,需要交换整个地址空间,而线程之间切换只是执行环境的改变,因此效率较高。整体而言,在Windows系统中,多线程优于多进程,毕竟Windows系统是从多线程开始的。

在Linux系统中,采用POSIX标准,Unix家族都是从多进程过来的。多进程调度开销比多线程调度开销,没有显著区别。

一个形象的比喻,

多进程是立体交通系统,虽然造价高,上坡下坡多耗点油,但是不堵车。

多线程是平面交通系统,造价低,但红绿灯太多,老堵车。

所谓的耗油多是指CPU的主频,但现在主频已不是问题,而内存也是越来越大。我们更希望行车过程畅通无阻。

3 线程栈

线程栈用于维护线程在执行代码时需要的所有函数参数和局部变量。在32位的系统中,进程中,线程最多能开多少个?

这个没有固定的答案,

线程的个数 =  进程用户空间/线程栈的大小。

在Windows平台默认的栈大小为1M,以此计算,理论上,可以开辟2GB/1M=2048个线程。但实际上,是无法做到的。因为有其他部分的消耗。

在Linux平台,如Fedora 10,利用ulimit -a指令可以查看堆栈的大小,结果为

stack size              (kbytes, -s) 10240
也就是10M。以此计算,最多开辟2GB/10MB=204个线程。另外查阅文档,反映Linux平台的栈默认大小应该是8192KB,而不是10M。

 

【实例剖析】

到底可以开多少个,不妨测试一下:

测试环境:Fedora10+虚拟机+512MB(虚拟内存估计是1024MB)

test.c

[html] view plain copy


  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <pthread.h>  
  4. #include <assert.h>  
  5.   
  6. void *start_routine(void *param)  
  7. {  
  8.     int data = *(int *)param;  
  9.     printf(“%s:%d\n”, __func__, data);  
  10.     return NULL;  
  11. }  
  12.   
  13. #define THREADS_NR 1024  
  14. void create_test_threads()  
  15. {  
  16.     int i = 0;  
  17.     int ret1 = 0;  
  18.     void *ret2 = NULL;  
  19.   
  20.     pthread_t ids[THREADS_NR] = {0};  
  21.       
  22.     for(i = 0; i < THREADS_NR; i++)  
  23.     {  
  24.         ret1 = pthread_create(ids + i, NULL, start_routine, &i);  
  25.     }  
  26.   
  27.     for(i = 0; i < THREADS_NR; i++)  
  28.     {  
  29.         pthread_join(ids[i], &ret2);  
  30.     }  
  31.   
  32.     return ;  
  33. }  
  34.   
  35. int main(int argc, char **argv)  
  36. {  
  37.     create_test_threads();  
  38.   
  39.     return 0;  
  40. }  


Makefile

[html] view plain copy


  1. src = test.c  
  2. target = test  
  3. temp = $(wildcard *~)  
  4. flag = PTHREAD_TEST  
  5.   
  6. all:$(src)  
  7.     gcc -g -pthread -D(flag)&nbsp;^ -o $(target)  
  8.   
  9. clean:  
  10.     rm (temp)&nbsp;(target)  


运行结果

[html] view plain copy


  1. start_routine:300  
  2. start_routine:301  
  3. start_routine:302  
  4. start_routine:303  
  5. start_routine:304  
  6. 段错误  

 

实验证实在该的环境中,最多可以开辟305个线程。利用GDB调试:

gdb test

[html] view plain copy


  1. start_routine:303  
  2. [Thread 0xbe409b90 (LWP 11075) exited]  
  3. [New Thread 0xbee0ab90 (LWP 11076)]  
  4. start_routine:304  
  5. [Thread 0xbee0ab90 (LWP 11076) exited]  
  6. [New Thread 0xbf80bb90 (LWP 11077)]  
  7. start_routine:565  
  8. [Thread 0xbf80bb90 (LWP 11077) exited]  
  9.   
  10. Program received signal SIGSEGV, Segmentation fault.  
  11. 0x00581b07 in pthread_join () from /lib/libpthread.so.0  
  12. Missing separate debuginfos, use: debuginfo-install glibc-2.9-2.i686  
  13. (gdb) bt  
  14. #0  0x00581b07 in pthread_join () from /lib/libpthread.so.0  
  15. #1  0x0804859f in create_test_threads () at test1.c:29  
  16. #2  0x080485d1 in main () at test1.c:37  
  17. (gdb) frame 1  
  18. #1  0x0804859f in create_test_threads () at test1.c:29  
  19. 29          pthread_join(ids[i], &ret2);  
  20. (gdb) p ret1  
  21. $4 = 11  
  22. (gdb) p ret2  
  23. $5 = (void *) 0x0  


错误发生在创建时,错误码为11

查看errno.h

利用find查看路劲

(1)  find / -name errno.h 2>/dev/null

[html] view plain copy


  1. /usr/src/kernels/2.6.27.5-117.fc10.i686/include/linux/errno.h  
  2. /usr/src/kernels/2.6.27.5-117.fc10.i686/include/asm-x86/errno.h  
  3. /usr/src/kernels/2.6.27.5-117.fc10.i686/include/asm-generic/errno.h  

(2) 查看源文件

执行

cat /usr/src/kernels/2.6.27.5-117.fc10.i686/include/asm-generic/errno.h

发现11定义在同级目录下errno-base.h文件

查看

cat  /usr/src/kernels/2.6.27.5-117.fc10.i686/include/asm-generic/errno-base.h

[html] view plain copy


  1. #define EAGAIN          11      /* Try again */  

利用man pthread_create查看,

[html] view plain copy


  1. ERRORS  
  2.        The pthread_create() function shall fail if:  
  3.   
  4.        EAGAIN The system lacked the  necessary  resources  to  create  another  
  5.               thread,  or  the  system-imposed  limit  on  the total number of  
  6.               threads in a process {PTHREAD_THREADS_MAX} would be exceeded.  
  7.   
  8.        EINVAL The value specified by attr is invalid.  
  9.   
  10.        EPERM  The caller does not  have  appropriate  permission  to  set  the  
  11.               required scheduling parameters or scheduling policy.  
  12.   
  13.        The  pthread_create()  function  shall  not  return  an  error  code of  
  14.        [EINTR].  
  15.   
  16.        The following sections are informative.  


说明是内存不足的问题。