Eri*_*ric 23 linux hard-drive process file-io
当我将命令的输出重定向到一个文件(例如,echo Hello > file
)时,该文件是否能保证在命令退出后立即具有此类数据?或者在命令退出和写入文件的数据之间仍然有一个非常小的窗口?我想在命令退出后立即读取文件,但我不想读取空文件。
mta*_*tak 23
如果应用程序没有任何内部缓存,则更改将立即写入文件。你的例子也是如此。该文件是内存中的一个逻辑实体,将立即更新。对文件的任何后续操作都将看到程序所做的更改。
但是,这并不意味着更改已写入物理磁盘。这些更改可能会留在操作系统文件系统缓存或硬件缓存中。要刷新文件系统缓冲区,请使用该sync
命令。
我想在命令退出后立即读取文件,但我不想读取空文件。
您不应该在这里遇到任何实际问题。
Sim*_*ter 22
涉及多层缓冲区/缓存。
CPU 缓存。
数据是一个字节一个字节地放在一起,存储在 CPU 缓存中。如果 CPU 缓存已满并且有一段时间没有访问数据,则包含我们数据的块可能会被写入主内存。这些在大多数情况下对应用程序员是隐藏的。
进程内缓冲区。
在收集数据的过程中会留出一些内存,因此我们需要尽可能少地向操作系统发出请求,因为这相对昂贵。该进程将数据复制到这些缓冲区,这些缓冲区可能再次由 CPU 缓存支持,因此无法保证将数据复制到主内存。应用程序需要显式刷新这些缓冲区,例如使用 fclose(3) 或 fsync(3)。exit(3) 函数也在进程终止之前执行此操作,而 _exit(2) 函数没有执行此操作,这就是为什么手册页中有一个很大的警告,该函数仅在您知道自己是什么时才调用它正在做。
内核缓冲区
然后操作系统保留自己的缓存,以尽量减少它需要发送到磁盘的请求数量。这个缓存不特别属于任何进程,所以里面的数据可能属于已经完成的进程,而且由于所有访问都经过这里,如果到达这里,下一个程序就会看到数据。内核将在有时间或明确要求时将此数据写入磁盘。
驱动器缓存
磁盘驱动器本身也保留缓存以加快访问速度。这些写入速度相当快,并且有一个命令将剩余数据写入缓存中并在完成时报告,操作系统在关机时使用该命令以确保在断电前没有数据未被写入。
对于您的应用程序,将数据注册在内核缓冲区中就足够了(此时实际数据可能仍然存在于 CPU 缓存中,并且可能尚未写入主内存):“echo”进程终止,这意味着任何进程内缓冲区必须已被刷新并将数据移交给操作系统,然后当您启动一个新进程时,可以保证操作系统会在询问时返回相同的数据。
Kon*_*lph 21
进程退出时缓冲区会自动刷新到磁盘吗?
一般来说,答案是否定的。
这取决于命令。正如其他答案所提到的,如果命令不在内部缓冲数据,则在命令终止时所有数据都将可用。
但大多数(如果不是全部)标准 I/O 库在默认情况下(在某种程度上)都会缓冲 stdout,并在应用程序关闭时对自动刷新缓冲区提供不同的保证。
C 保证正常退出将刷新缓冲区。“正常退出”意味着exit
被调用——要么是显式的,要么是从main
. 然而,异常退出可以绕过这个调用(因此留下未刷新的缓冲区)。
这是一个简单的例子:
#include <signal.h>
#include <stdio.h>
int main() {
printf("test");
raise(SIGABRT);
}
Run Code Online (Sandbox Code Playgroud)
如果你编译这个并执行它,test
会不会一定被写入stdout。
其他编程语言给更少的保证:Java中,例如,是否没有在程序终止时自动刷新。如果输出缓冲区包含未终止的行,则它可能会丢失,除非System.out.flush()
明确调用。
这就是说,你的问题问的身体的东西稍有不同:如果文件中的数据到达可言,应该命令终止(须在其他的答案中描述的注意事项)后立即这样做。
我认为还没有任何问题充分解决这个问题:
我想在命令退出后立即读取文件,但我不想读取空文件。
正如其他答案所解释的那样,行为良好的程序会在进程正常终止之前刷新其内部文件缓冲区。之后,数据在写入持久存储之前可能仍留在内核或硬件缓冲区中。然而,Linux 的文件系统语义保证所有进程以与内核相同的方式查看文件内容,包括内部缓冲区1。
这通常是通过每个文件对象最多有一个内核缓冲区来实现的,并且要求所有文件访问都通过这个缓冲区。
如果一个进程读取一个文件,内核将把缓冲区的内容呈现给进程,如果请求的文件部分当前在缓冲区中;如果不是,内核会从底层存储介质中获取数据并将其放入缓冲区,然后返回上一步。
如果进程写入文件,则数据首先放置在该文件的内核缓冲区中。最终缓冲区内容将被刷新到存储。同时,读取访问从同一个缓冲区得到满足(见上文)。
1至少对于常规文件、目录和符号链接。FIFO 和套接字是另一回事,因为它们的内容无论如何都不会持久存储。有一些特殊情况的常规文件,其内容取决于询问者;示例是 procfs 和 sysfs 中的文件(认为/proc/self
这是读取符号链接的进程的进程 ID 的符号链接)。
假设您的命令是由使用 C 运行时库的某个程序执行的,在某些时候它应该调用fclose
以关闭打开的文件。
fclose
C 函数的手册页说:
注意 请注意, fclose() 仅刷新 C 库提供的用户空间缓冲区。为了确保数据物理存储在磁盘上,内核缓冲区也必须刷新,例如,使用 sync(2) 或 fsync(2)。
并且手册页fflush
具有相同的注释。手册页close
说:
成功关闭并不能保证数据已成功保存到磁盘,因为内核会延迟写入。当流关闭时,文件系统刷新缓冲区并不常见。如果您需要确保数据是物理存储的,请使用 fsync(2)。(此时将取决于磁盘硬件。)
请注意,即使数据未同步到驱动器,其他进程也可以使用该数据。也许这对你来说已经足够了。
如果您有疑问,请编写一个测试。
归档时间: |
|
查看次数: |
14037 次 |
最近记录: |