全部博文(174)
分类: LINUX
2009-03-23 21:08:40
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
就我的理解来看,我认为有时候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是寄存器变量,不是内存,所以没有地址的概念,不可以引用。