本文重点介绍一下Linux操做系统进程(线程)与文件描述符、文件的关系,具体到内核部分就是task_struct、files_struct、file和inode的关系。node
咱们在Linux用户态开发都清楚,打开一个文件以后会返回一个文件描述符,并且每一个进程打开文件的数量是有限的。这个具体是什么什么缘由?数组
若是咱们深刻到Linux操做系统的内核,就会知道其中的奥秘。在Linux操做系统,每一个用户态的进程在内核态都有一个对应的内核进程(线程),这个在内核中经过task_struct结构体标识,内核经过其实现对进程的调度。而在内核中对于文件的访问则是经过file和inode结构体实现的,其中包含这访问文件的关键信息(例如访问偏移)和方法(例如读写文件操做)。操作系统
fd=open(“/home/zhf/zhf/c_prj/itworld123.com”,O_RDWR);线程
以下图是典型的进程与文件的关系图,图中进程打开了两个不一样的文件。在进程结构体(task_struct)中有一个files_struct成员,其中保存这一个数组,这个数组的偏移量就是文件描述符,而其中的成员则是file结构体的指针。这样,经过用户态的整型的文件描述符能够很方便的找到管理文件的结构体(file)进而实现对文件的操做。本文为了方便说明,对files_struct结构体进行了简化处理,实际上该结构提要复杂不少。3d
进程(task_struct)与文件结构体(file)的关系清楚了,那么文件结构体又是怎么来的,它跟inode的关系是什么样的呢?如上图所示,每个file都有一个对应的inode的结构体。两种其实都对应着一个磁盘上的具体文件,但又有差别。file其实对应这一个打开文件的实例,而inode一一对应一个磁盘文件。也就是说一个磁盘文件对应的file在内存中可能有多份,而inode则只会有一份。后续咱们会详细解释具体实现。指针
咱们知道在Linux中进程都存在一些父子关系,并且子进程会继承父进程的不少内容。那么若是咱们fork出一个子进程,此时子进程会继承父进程文件相关的内容。若是咱们使用的是fork系统调用,此时子进程会建立一个新的files_struct实例,并将父进程的内容迁移过来,这里说迁移,而不是拷贝,其缘由是并非原封不懂的内存拷贝,而是会作一些处理。好比父进程中对file结构体的指向,在子进程中也会指向,且文件描述符一致,同时会增长file结构体实例的引用计数,确保使用关系的正确性。 cdn
先到这里,后续本文会继续讨论file结构体与inode及磁盘数据的关系。blog