big*_*iao 6 c unix posix atomic
我正在阅读APUE(UNIX 环境中的高级编程),当我看到 $3.11 时遇到了这个问题:
if (lseek(fd, 0L, 2) < 0) /* position to EOF */
err_sys("lseek error");
if (write(fd, buf, 100) != 100) /* and write */
err_sys("write error")
APUE 说:
这适用于单个进程,但如果多个进程使用此技术附加到同一个文件,则会出现问题。.......这里的问题是我们的“定位到文件末尾并写入”的逻辑操作需要两个单独的函数调用(正如我们所展示的)。任何需要多个函数调用的操作都不能是原子的,因为内核总是有可能在两次函数调用之间暂时挂起进程。
它只是说cpu会在lseek和之间的函数调用之间切换write,我想知道它是否也会在一半write操作之间切换?或者更确切地说,是write原子的?如果线程A写"aaaaa",线程B写"bbbbb",结果会是"aabbbbbaaa"?
更重要的是,在APUE说pread并且pwrite都是原子操作之后,这是否意味着这些函数使用mutex或lock内部是原子的?
将 Posix 语义称为“原子”可能过于简单化了。Posix 要求以某种顺序进行读写:
写入可以相对于其他读取和写入进行序列化。如果 a
read()of 文件数据可以被证明(以任何方式)发生在 awrite()of 数据之后,则它必须反映这一点write(),即使调用是由不同的进程进行的。类似的要求适用于对同一文件位置的多次写入操作。这是保证数据从write()调用到后续read()调用的传播所必需的。(从原理的的部分的Posix规范pwrite和write)
APUE中提到的原子性保证是指使用O_APPEND标志,强制写入在文件末尾执行:
如果
O_APPEND设置了文件状态标志的标志,则文件偏移量应在每次写入之前设置为文件末尾,并且在更改文件偏移量和写入操作之间不应发生中间文件修改操作。
关于preadand pwrite,APUE 说(当然是正确的)这些接口允许应用程序以原子方式寻找和执行 I/O;换句话说,无论其他进程做什么,I/O 操作都将发生在指定的文件位置。(因为位置是在调用本身中指定的,不会影响持久文件位置。)
POSIX的测序保证如下(从描述的write()和pwrite()功能):
在对常规文件的 write() 成功返回后:
read()由该写入修改的文件中每个字节位置的任何成功都应返回该位置的 write() 指定的数据,直到再次修改此类字节位置。
write()文件中相同字节位置的任何后续成功都将覆盖该文件数据。
如基本原理中所述,此措辞确实保证两个同时write调用(即使在不同的不相关进程中)不会交错数据,因为如果数据在最终成功的写入期间交错,则无法提供第二个保证。如何做到这一点取决于实施。
必须注意的是,并非所有文件系统都符合 Posix,模块化 OS 设计允许多个文件系统在单个安装中共存,这使得内核本身无法提供write适用于所有可用文件系统的保证。网络文件系统特别容易发生数据竞争(并且本地互斥锁也无济于事),正如 Posix 所提到的(在引自 Rationale 的段落末尾):
此要求对于网络文件系统尤其重要,其中某些缓存方案违反了这些语义。
第一个保证(关于后续读取)需要文件系统中的一些簿记,因为已成功“写入”内核缓冲区但尚未同步到磁盘的数据必须透明地可供从该文件读取的进程使用。这还需要对内核元数据进行一些内部锁定。
由于写入常规文件通常是通过内核缓冲区完成的,并且实际上将数据同步到物理存储设备绝对不是原子的,因此提供这些保证所需的锁不必非常持久。但是它们必须在文件系统内完成,因为 Posix 措辞中没有任何内容限制在单线程进程中同时写入的保证。
在一个多线程进程,Posix的确实需要read(),write(),pread()而pwrite()当他们在常规文件上(或符号链接)操作是原子的。有关必须遵守此要求的接口的完整列表,请参阅线程与常规文件操作的交互。
| 归档时间: | 
 | 
| 查看次数: | 3393 次 | 
| 最近记录: |