文件句柄、文件描述符与进程和多线程的那些事

本文出至:http://my.oschina.net/iuranus/blog/330397?fromerr=x1SVuj0Z

文件句柄(摘抄的一些概念,帮助理解):

句柄是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传给启动的线程的情况是一样的。

 

另外关注上述图片表的解释如下:

时间: 2024-11-14 12:52:23

文件句柄、文件描述符与进程和多线程的那些事的相关文章

[转] linux系统文件流、文件描述符与进程间关系详解

http://blog.sina.com.cn/s/blog_67b74aea01018ycx.html linux(unix)进程与文件的关系错综复杂,本教程试图详细的阐述这个问题. 包括: 1.linux多/单进程与多/单文件对于文件流和描述符在使用时的关联情况及一些需要注意的问题. 2.fork,vfork流缓冲等对文件操作的影响. 1.linux文件系统结构 首先补充一点基础知识,了解一下linux文件系统.如下图所示: 图1 磁盘,分区和文件系统 应该明白,上图所示结构是硬盘中文件存放

通过UNIX域套接字传递文件描述符

传送文件描述符是高并发网络服务编程的一种常见实现方式.Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现.本文详细说明一下传送文件描述符的应用. 1. TCP服务器程序设计范式 ??开发一个服务器程序,有较多的的程序设计范式可供选择,不同范式有其自身的特点和实用范围,明了不同范式的特性有助于我们服务器程序的开发.常见的TCP服务器程序设计范式有以下几种: 迭代服务器 并发服务器,每个客户请求fork一个子进程 预先派生子进程,每个子进程无保护地调用accept 预先

UNIX进程之间传递文件描述符recvmsg与sendmsg

socketpair: 功能:创建一个全双工的流管道 原型 int socketpair(int domain, int type, int protocol, int sv[2]); 参数 domain: 协议家族 type: 套接字类型 protocol: 协议类型 sv: 返回套接字对 返回值:成功返回0:失败返回-1 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t recvmsg(int

0707 父子进程之间传递文件描述符

1 /************************************************************************* 2 > File Name: pass_fd.c 3 > Author:Monica 4 > Mail:[email protected] 5 > Created Time: Mon 07 Jul 2014 09:52:49 PM CST 6 ********************************************

调整进程的最大linux文件描述符

1.介绍 ulimit 命令提供了针对 shell和或由该 shell 启动的进程占用资源的控制. 持久化修改生效是在/etc/security/limits.conf中进行数据写入. 写入的格式为:<domain><type><item><value> domain:用户名/用户组名/其他(查看man limits.conf) type: hard / soft ,分别指实际最大值类型和预警值类型,一个是max,一个是threshold,在threshol

进程间传递文件描述符

下面的实例展示了如何使用Unix域套接字在进程间传递文件描述符 参考文献:1) <Unix网络编程> 2)  http://book.51cto.com/art/200912/168560.htm 最近学习了使用Unix域套接字在进程间传递文件描述符,仿照参考资料,自己也写了简单的程序来实践这种技术. 其他不多说了,具体理论知识参见参考资料,开始我自己的程序介绍(在OpenSolaris 2009.06平台上测试): 1  程序作用说明:父进程,子进程以及另外一个进程向同一个文件的文件描述符向

fork()父子进程文件描述符的关系

父子进程共享文件描述符:此说法,其实是父子进程共享 文件表项(父进程和子进程共享同一个file table entry) 由于子进程是父进程的拷贝,子进程会拷贝父进程的进程描述符中的文件描述符表,可以说继承父进程的文件描述字(files_struct中的struct file *fd_array[NR_OPEN_DEFAULT]的拷贝) 如果我们没有调用exec函数,则我们父子进程的代码段,堆栈,数据段都完全相同(因为是拷贝),所以此时我们的子进程可以使用fork()之前的fd值,虽然此时fd是

C/C++ 父子进程之间的文件描述符问题

在C程序中,文件由文件指针或者文件描述符表示.ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文件描述符.下面重点来说下,文件描述符是如何工作的. 文件描述符相当于一个逻辑句柄,而open,close等函数则是将文件或者物理设备与句柄相关联.句柄是一个整数,可以理解为进程特定的文件描述符表的 索引.先介绍下面三个概念,

进程间传递文件描述符——sendmsg和recvmsg函数

先引入一个例子,该程序的目的是子进程向父进程传递文件描述符,并通过该文件描述符读取buf. #include <func.h> int main(){ int fds[2]; pipe(fds); if(!fork()){ close(fds[1]); int fd; read(fds[0], &fd, sizeof(fd)); printf("child fd = %d\n", fd); char buf[128] = {0}; read(fd, buf, siz