学习Linux系统编程-Day(9)

1.在Linux系统的设计中,所有的系统调用都是以原子形式存在的,所谓系统调用的原子性,就是指系统调用在执行过程中的所有步骤都会作为独立操作一次性执行完毕,而不会被其他线程中断。原子操作是规避竞争状态的有效手段之一,处于竞争状态下的多个线程其执行结果是不确定的,这取决于CPU的调度,为了防止处于内核态的系统调用出现竞争,故而规定所有的系统调用都是原子操作,这本质上还是通过屏蔽中断来实现的。

2.在文件系统中也存在很多关于原子操作和竞争的问题,书上就这一点举了两个不好的使用习惯和例子,并讲述了如何使用open系统调用标志字的方法来规避竞争状态。其一是独占式创建文件,其二是规避脏写入
之前提到过,open系统调用可以使用O_CREAT标志来在文件不存在的情况下创建文件,所以这其中包含两个动作,也就是检测文件是否存在创建文件。在一些情况下,这两个动作中间可能会被外来线程打断,当返回时程序会继续创建这个文件,并认为文件的归属权属于自己,这是一种错误的情况,因为外来线程可能也在创建一个相同的文件。
在这里插入图片描述
要避免这种情况只需要把open系统调用的标志字换成O_CREAT | O_EXECL,这样就可以将检测和创建文件两个动作“打包”成一个原子化的操作,在多线程情况下可以规避竞争状态。

写脏数据有可能发生在多个线程向同一文件尾部追加数据的情况,这种情况下尽可能使用O_APPEND标志来打开文件并写入数据,这个标志保证了在向文件尾部追加数据之前不被打断,即保证了操作的原子性。其他的写法,比如首先用lseek将文件指针指向文件尾再写入的方法就不可以保证原子性了,会导致多线程写入时数据被覆盖,导致脏写入问题。

3.在文件操作中,fcntl系统调用是一个非常重要的存在。它可以对一个已经打开的文件描述符进行一系列操作,比如读取文件描述符的状态字flags并修改。之前提过,flags标志字按功能可以分为文件访问模式文件创建标志已打开文件的状态标志。其中,已打开文件的状态表示就是fcntl发挥功能的地方,既可以读取这些状态,还可以对其中的一部分作出修改。fcntl函数原型如下:
在这里插入图片描述
fd是将要操作的文件标识符,cmd是要执行的操作命令,这应该是一组预定义的宏,比如F_GETFL(get flags)用来获取文件标识符fd的状态字flags,F_SETFL(set flags)用来设置状态字flags。

读取完状态字之后,既可以来测试状态字中是否含特定的标志,还可以来设置/清除对应的标志位。
测试是否存在标志位时,只需将flags与对应位相与即可:
在这里插入图片描述
测试访问模式时方法不同,因为O_RDONLY(0)、 O_WRONLY(1)和 O_RDWR(2)是三个独立的信息位,所以只能单独测试,首先要将flags与O_ACC_MODE(Access Mode)相与。再测试到底属于上述三种状态的哪一种,用例如下:
在这里插入图片描述
测试完之后如果需要修改或者删除标志,只需要令flags与对应标志位(清除时是标志位的取反相与就可以了:
在这里插入图片描述
4.有三个内核数据结构用来管理文件,分别是进程级的文件描述符表系统级的打开文件表文件系统上的i-node表(索引节点表 索引节点的相关介绍,其中存放了关于文件的重要元信息)。它们之间的关系如下图所示:
在这里插入图片描述
从上图可以看到,文件描述符标志是被进程私有的,每一个文件描述符都有一个对应的标志来控制文件标识符的操作。而同一个进程中的不同文件标识符,或者不同进程中的文件标识符可以指向同一个打开文件句柄(打开文件句柄也就是打开文件表的一个表项),那这时所有对打开文件读写指针的操作和写入都是被所有进程同时看见的,因为它们共享同一打开文件句柄。不同的打开文件句柄可能指向同一索引节点,进而它们本质上是同一磁盘数据存储区。

猜你喜欢

转载自blog.csdn.net/zzy980511/article/details/115343029