Linux文件共享(五)——线程共享文件
在谈论线程之间共享文件之前,我想首先简单的介绍下linux线程的实现。最初的进程定义都包含程序、资源及其执行三部分,其中程序通常指代码,资源在操作系统层面上通常包括内存资源、IO资源、信号处理等部分,而程序的执行通常理解为执行上下文,包括对cpu的占用,后来发展为线程。在线程概念出现以前,为了减小进程切换的开销,操作系统设计者逐渐修正进程的概念,逐渐允许将进程所占有的资源从其主体剥离出来,允许某些进程共享一部分资源,例如文件、信号,数据内存,甚至代码,这就发展出轻量进程的概念。Linux内核在2.0.x版本就已经实现了轻量进程,应用程序可以通过一个统一的clone()系统调用接口,用不同的参数指定创建轻量进程还是普通进程。在内核中,clone()调用经过参数传递和解释后会调用do_fork(),这个核内函数同时也是fork()、vfork()系统调用的最终实现:在do_fork()中,不同的clone_flags将导致不同的行为,对于LinuxThreads,它使用(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)参数来调用clone()创建"线程",表示共享内存、共享文件系统访问计数、共享文件描述符表,以及共享信号处理方式。(其中前三个标志对应共享的数据结构分别为task_struct中的mm,fs,files)。
(1) CLONE_VM
do_fork()需要调用copy_mm()来设置task_struct中的mm和active_mm项,这两个mm_struct数据与进程所关联的内存空间相对应。如果do_fork()时指定了CLONE_VM开关,copy_mm()将把新的task_struct中的mm和active_mm设置成与current的相同,同时提高该mm_struct的使用者数目(mm_struct::mm_users)。也就是说,轻量级进程与父进程共享内存地址空间。
(2) CLONE_FS(这个和我们接下来的讨论有关)
task_struct中利用fs(struct fs_struct *)记录了进程所在文件系统的根目录和当前目录信息,do_fork()时调用copy_fs()复制了这个结构;而对于轻量级进程则仅增加fs- count计数,与父进程共享相同的fs_struct。也就是说,轻量级进程没有独立的文件系统相关的信息,进程中任何一个线程改变当前目录、根目录等信息都将直接影响到其他线程。
(3) CLONE_FILES(这个和我们接下来的讨论也有关)
一个进程可能打开了一些文件,在进程结构task_struct中利用files(struct files_struct *)来保存进程打开的文件结构(struct file)信息,do_fork()中调用了copy_files()来处理这个进程属性;轻量级进程与父进程是共享该结构的,copy_files()时仅增加files- count计数。这一共享使得任何线程都能访问进程所维护的打开文件,对它们的操作会直接反映到进程中的其他线程。
(4) CLONE_SIGHAND
每一个Linux进程都可以自行定义对信号的处理方式,在task_struct中的sig(struct signal_struct)中使用一个struct k_sigaction结构的数组来保存这个配置信息,do_fork()中的copy_sighand()负责复制该信息;轻量级进程不进行复制,而仅仅增加signal_struct::count计数,与父进程共享该结构。也就是说,子进程与父进程的信号处理方式完全相同,而且可以相互更改。
4.2 线程打开文件分析有了以上分析,我们就可以画出线程间对应的打开文件数据结构的关系,如下图所示。
我们看到,线程间所有文件结构都为共享资源,不但“文件表项”(file对象)是共享的,就连“文件描述符表”(files_struct结构)也是共享的。
总结:线程的创建仅仅增加的是files和fs的引用计数,“文件打开计数”(file对象的引用计数)并没有增加,所以任何一个线程对打开的文件执行close操作,文件都将关闭(文件打开计数为1的情况)。但是如果线程不进行打开文件的关闭,则文件直到进程结束时才会关闭,这就是使用多线程实现tcp服务器时,服务线程必须要显示调用close的原因,否则永远不会发送FIN终止链接(因为主线程一直处于监听不会结束)。
相关文章
- [Linux] linux文件系统学习
- 每天一个linux命令(10):cat 命令
- linux编译安装mysql5.1.x
- linux机器之间拷贝和同步文件命令
- linux下如何使用docker二进制文件安装_docker离线安装
- Linux netstat命令详解
- ARM-Linux移植之(四)——根文件系统构建
- Linux启动/停止/重启Mysql数据库的方法
- linux文件描述符open file descriptors与open files的区别
- linux(centos8):使用cgroups做资源限制
- Linux文件权限管理命令
- linux fedora安装snap包管理器通过snap安装obs-studio
- Linux 格式化输出当前系统时间
- Linux上传与下载工具介绍
- Linux管道
- Linux下Qt调用共享库文件.so
- linux最大文件句柄数量之(file-max ulimit -n limit.conf)
- L36.linux命令每日一练 -- 第五章 Linux信息显示与搜索文件命令 -- locate和updatedb
- L34.linux命令每日一练 -- 第五章 Linux信息显示与搜索文件命令 -- echo和watch
- L33.linux命令每日一练 -- 第五章 Linux信息显示与搜索文件命令 -- du和date
- L31.linux命令每日一练 -- 第五章 Linux信息显示与搜索文件命令 -- uname和hostname
- L22.linux命令每日一练 -- 第三章 文件过滤及内容编辑处理命令 -- uniq和wc命令
- Linux内核中ideapad-laptop.c文件全解析2
- conda安装r Linux系统中 linux中安装r
- Linux安装conda Ubuntu安装conda Linux安装百度云 Ubuntu安装百度云 服务器安装百度云 Linux上传到百度云 Linux上传文件到百度云 Linux从百度云下载
- LINUX 使用 smbclient 获取windows 共享目录的文件 详解
- 学习C++:Linux下Clion安装使用、汉化及环境配置
- linux中python安装scanpy安装进行单细胞分析scrnaseq