文件句柄、文件描述符与进程和多线程的那些事
http://my.oschina.net/iuranus/blog/330397
文件句柄(摘抄的一些概念,帮助理解):
句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。
如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?
为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。
句柄是操作系统在生成对象时分配给对象的唯一标识。 通过句柄可以获取操作系统提供的服务。句柄不同于指针,如果你得到一个对象的指针,那你就可以在此对象上为所欲为了。于是系统不给你指针,而给用户一个加了限制的,用于跟踪对象的指针的标识——句柄。系统使用句柄向外提供服务就相对安全了。
总结:
1、无论是文件句柄(Windows中概念),还是文件描述符(linux中概念),其最终目的都是用来定位打开的文件在内存中的位置,只是它们映射的方式不一样。
2、文件句柄定位到的是文件对象,而非文件。而文件对象是对这个文件的一些状态、属性的封装,例如读取到的文件位置等。
3、关于在进程、线程下,这个时候用文件句柄不好阐述,可以把文件句柄理解成下图中的文件描述符,如下图:
每个进程有各自独立的文件描述符,打开不同的文件也都会有不同的打开文件表项,并且指向不同的v-node表项。
此时没有共享文件,并且每个描述符对应一个不同的文件。
不同的进程多次open一个文件,则会产生不同的打开文件表项,但最终指向的是同一个文件的v-node标项。
此时,多个描述符也可以通过不同的文件表表项来引用同一个文件。例如,如果以同一个filename调用open函数两次,就会发生这种情况。关键思想是:每个描述符都有它自己的文件位置,所以对不同描述符的读操作可以从文件的不同位置获取数据。
如果在多线程中打开同一个文件(不同于在主线程中打开一个文件,并将fd=open(file)的fd参数传给线程),则每个线程会有各自的文件描述符,按照上一条关键思想,这每个线程也会有保存自己的读取位置,互不影响。
深入理解计算机系统里还有这么段话:因为每个进程都有自己HANDLE的存储空间);如果是同一个进程的线程,因为同基于I/O多路复用的流一样,多个线程运行在单一进程的上下文中,共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件(句柄)。这个应该也是指的进程已经打开文件,则线程共享打开的文件。
如果在调用fork之前父进程已经打开文件,则fork后子进程有一个父进程描述符表的副本。父子进程共享相同的打开文件集合,因此共享相同的文件位置。
这个情况跟主线程已经open文件,并把fd传给启动的线程的情况是一样的。
另外关注上述图片表的解释如下:
这下清楚不少,但是昨天关于Python中myFile = open('fileLoc','r')的情况还不能照搬理解,因为Python的封装,open后返回的是文件对象,至于文件对象的本质,还需要进一步研究。