Chinaunix首页 | 论坛 | 博客
  • 博客访问: 501347
  • 博文数量: 174
  • 博客积分: 8001
  • 博客等级: 中将
  • 技术积分: 1840
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-04 19:30
文章分类

全部博文(174)

文章存档

2011年(1)

2010年(24)

2009年(149)

我的朋友

分类: LINUX

2009-03-23 21:08:40

首先,当然要弄清楚进程和线程的区别和联系:
在现代操作系统中,进程支持多线程。进程是资源管理的最小单元;而线程是程序执行的最小单元。一个进程的组成实体可以分为两大部分:线程集合和资源集合。进程中的线程是动态的对象;代表了进程指令的执行。资源,包括地址空间、打开的文件、用户信息等等,由进程内的线程共享。线程有自己的私有数据:程序计数器,栈空间以及寄存器(可以认为线程自己保存着CPU的状态,而和其他线程共享内存空间)。

传统单线程进程的缺点:
1.  现实中有很多需要并发处理的任务,如数据库的服务器端、网络服务器、大容量计算等。
2.  传统的UNIX进程是单线程的,单线程意味着程序必须是顺序执行,不能并发;既在一个时刻只能运行在一个处理器上,因此不能充分利用多处理器框架的计算机。
3.  如果采用多进程的方法,则有如下问题:
a. fork一个子进程的消耗是很大的,fork是一个昂贵的系统调用,即使使用现代的写时复制(copy-on-write)技术。
b. 各个进程拥有自己独立的地址空间,进程间的协作需要复杂的IPC技术,如消息传递和共享内存等。

多线程的优缺点:
多线程的优点和缺点实际上是对立统一的。支持多线程的程序(进程)可以取得真正的并行(parallelism),且由于共享进程的代码和全局数据,故线程间的通信是方便的。它的缺点也是由于线程共享进程的地址空间,因此可能会导致竞争,因此对某一块有多个线程要访问的数据需要一些同步技术。
下面是摘文:

We've seen how a program can fork a child process. The child process is initially running its parent's program, with its parent's virtual memory, file descriptors, and so on copied. The child process can modify its memory, close file descriptors, and the like without affecting its parent, and vice versa. When a program creates another thread, though, nothing is copied. The creating and the created thread share the same memory space, file descriptors, and other system resources as the original. If one thread changes the value of a variable, for instance, the other thread subsequently will see the modified value. Similarly, if one thread closes a file descriptor, other threads may not read from or write to that file descriptor. Because a process and all its threads can be executing only one program at a time, if any thread inside a process calls one of the exec functions, all the other threads are ended (the new program may, of course, create new threads).

GNU/Linux implements the POSIX standard thread API (known as pthreads). All thread functions and data types are declared in the header file . The pthread functions are not included in the standard C library. Instead, they are in libpthread, so you should add -lpthread to the command line when you link your program.

就我的理解来看,我认为有时候C语言的一些高级概念,你还是要回到底层去思考。回到汇编来理解线程和进程的区别。

在写汇编代码的时候,我们要分配堆栈段,写数据段,写代码段,如果结合C对内存的管理来看,栈管理是集成在CPU的——它在概念上属于CPU,所以局部变量属于CPU范围的管理,事实上,你可以将栈看做是属于代码段的。虽然我不清楚这样是否合适,但是它是CPU范围的,所以是线程私有的。

而其他资源不是代码段范围的,例如堆内存,例如数据段(我认为C中的静态存储区属于这个范围——错了请指教),它自然不是CPU管理的,所以不是线程私有的。而文件描述符等系统资源,是系统行为,所以不是代码段范围的。

而堆栈段,相应于C中的堆内存,也不是代码段的,所以不是线程私有的。

事实上,说了这么多,都是论述属于CPU的就是线程私有的,而不属于CPU的就不是线程私有的。因为线程是指令执行的最小单元,它保留一个CPU的快照。

而进程不但保留CPU的快照,而且保留了资源。这就是线程和进程的不同。

虽然说,从并行的角度来讲,线程和进程都能做到。但是事实上,进程是通过线程来做到的。一个进程总会有一个线程。并行——只是线程的事情。

线程是代码段的一部分,我是这样理解的。一个程序可以将不同的代码段交给不同线程处理。而进程,是不同的代码段。(使用pthread_create就像是传递一个函数指针而调用一个函数,不同的是,它是和目前的函数主体并行的。

但是栈虽然说可以归为代码段的,但是并不是说一个线程引用另一个线程的栈是非法的,因为它们不是寄存器变量,所以它们事实上是存在内存之中,由于线程拥有共同的虚拟内存地址,所以它们之间是可以互引用的,通过pthread_creat的arg,但是这样可能会出现问题:

#include  
#include  
 
/* Parameters to print_function. */ 
 
struct char_print_parms 
{
 /* The character to print.*/ 
 char character; 
 /* The number of times to print it.  */ 
 int count; 
}; 
 
/* Prints a number of characters to stderr, as given by PARAMETERS, 
   which is a pointer to a struct char_print_parms. */ 
 
void* char_print (void* parameters) 
{
    /* Cast the cookie pointer to the right type.  */ 
    struct char_print_parms*  p = (struct char_print_parms*) parameters; 
    int i; 
 
    for (i = 0; i < p->count; ++i) 
      fputc (p->character,stderr); 
    return NULL; 
} 
 
/* The main program. */ 
 
int main () 
{
 pthread_t thread1_id; 
  pthread_t  thread2_id; 
  struct  char_print_parms  thread1_args; 
  struct  char_print_parms  thread2_args; 
 
  /*  Create  a  new  thread  to  print  30,000  'x's.  */ 
  thread1_args.character  =  'x'; 
  thread1_args.count  =  30000; 
  pthread_create  (&thread1_id,  NULL,  &char_print,  &thread1_args); 
 
  /*  Create  a  new  thread  to  print  20,000  o's.  */ 
  thread2_args.character  =  'o'; 
  thread2_args.count  =  20000; 
  pthread_create  (&thread2_id,  NULL,  &char_print,  &thread2_args); 
 
  return  0; 
}

But wait! The program has a serious bug in it. The main thread (which runs the main function) creates the thread parameter structures (thread1_args and thread2_args) as local variables, and then passes pointers to these structures to the threads it creates. What's to prevent Linux from scheduling the three threads in such a way that main finishes executing before either of the other two threads are done? Nothing! But if this happens, the memory containing the thread parameter structures will be deallocated while the other two threads are still accessing it.

所以,有些机制需要引入,但是我们这里不讨论。

说到这里,有些局部变量,如果声明为register,那么是否可以在不同线程间引用呢?

答案是:register是寄存器变量,不是内存,所以没有地址的概念,不可以引用。




阅读(601) | 评论(0) | 转发(0) |
0

上一篇:关于C的说明

下一篇:内存

给主人留下些什么吧!~~