File io 当其他进程在*nix系统上写入文件时,无法追加到该文件

File io 当其他进程在*nix系统上写入文件时,无法追加到该文件,file-io,unix,concurrentmodification,File Io,Unix,Concurrentmodification,我有一段非常简单的代码,它只是以一定的间隔将少量数据写入一个文件。一旦我的程序创建了该文件并附加了一些数据,当我在vim(或任何其他编辑器)中打开该文件并对其进行编辑时,我的过程似乎无法再更新该文件。我没有看到从系统调用返回任何错误。我尝试跟踪系统调用,即使文件没有更新,也没有发现任何奇怪的情况 由于每个进程都有自己的文件表条目,该条目具有当前偏移量,因此我所期望的只是一个输出文件,其中的数据散布在两个不合作进程的写入中(可能也是乱码)。但我观察到的是,一旦任何其他编辑器写入该文件,我的程序就无

我有一段非常简单的代码,它只是以一定的间隔将少量数据写入一个文件。一旦我的程序创建了该文件并附加了一些数据,当我在vim(或任何其他编辑器)中打开该文件并对其进行编辑时,我的过程似乎无法再更新该文件。我没有看到从系统调用返回任何错误。我尝试跟踪系统调用,即使文件没有更新,也没有发现任何奇怪的情况

由于每个进程都有自己的文件表条目,该条目具有当前偏移量,因此我所期望的只是一个输出文件,其中的数据散布在两个不合作进程的写入中(可能也是乱码)。但我观察到的是,一旦任何其他编辑器写入该文件,我的程序就无法再更新该文件

还有几个有趣的观察结果

1) 当我在输出文件中添加某些内容时,我的程序可以继续更新,没有问题

2) 当我自己的程序的多个实例写入同一个文件时,一切又恢复正常

我知道有强制锁定来防止多次写入,但我试图了解下面发生了什么。对于某些日志记录器(如系统日志、apache日志等),这种情况也会正常发生

有什么办法来解释这种行为吗?。还有关于如何进一步调试的提示吗

我的代码非常简单:

  1 int main(int argc, char** argv)
  2 {
  3     const char* buf;
  4     if(argc < 2)
  5         buf = "test->";
  6     else
  7         buf = argv[1];
  8 
  9     int fd; 
 10     if((fd = open("test.log", O_CREAT|O_WRONLY|O_APPEND, 0644)) == -1) {
 11         perror("Cannot open test.log");
 12         exit(1);
 13     }   
 14 
 15     int num_bytes = strlen(buf), num_bytes_written = -1; 
 16 
 17     while(1) {
 18         if((num_bytes_written = write(fd, buf, num_bytes)) == -1) {
 19             perror("Could not write to fd");
 20         }   
 21         fsync(fd);
 22         sleep(5);
 23     }   
 24 }   
1 int main(int argc,char**argv)
2 {
3常量字符*buf;
4如果(argc<2)
5 buf=“测试->”;
6其他
7 buf=argv[1];
8.
9 int fd;
10如果((fd=open(“test.log”,O|u create | O|u WRONLY | O|u APPEND,0644))==-1){
11 perror(“无法打开test.log”);
12出口(1);
13     }   
14
15 int num_bytes=strlen(buf),num_bytes_write=-1;
16
17而(1){
18如果((写入的字节数=写入(fd、buf、字节数))=-1){
19 perror(“无法写入fd”);
20         }   
21 fsync(fd);
睡眠22(5);
23     }   
24 }   

vim编辑器在文件的缓存版本上工作。它会在其他程序附加到原始文件时修改此缓存。使用vim保存时,将使用更新的缓存文件覆盖原始文件,并释放所有日志。

当vim(1)编辑器退出时,它可能会用已编辑的版本替换原始文件。您的进程保持原始文件处于打开状态,但该文件不再存在,因为它的目录项已被替换,因此,尚未打开该文件的进程无法访问该文件。您的进程现在正在附加到任何其他进程都无法访问的文件。一旦您的进程关闭文件,它将永远消失(除非您运行分区恢复程序)。

vim打开一个.swp文件并对其进行处理,覆盖原始文件等——同意;但我试图理解的是,为什么我的进程执行的任何写入操作都不会在文件中结束,即使在vim(或任何其他编辑器)完成写入并退出之后也是如此。(请记住,这个过程是在一个无限循环中定期写入一些数据)
set backupcopy=yes
将使Vim覆盖现有文件,而不是写入一个新文件并将其重命名为原始名称。@steve:不取消链接只会减少链接计数,只有当链接计数为零时,实际文件才会被删除?但尚不清楚的是,即使文件已被标记为取消链接,对仍然打开的文件描述符进行写入的结果。就像你说的,可能所有的数据都掉在地板上了,文件被标记为断开链接的那一刻?我猜write syscall不会检查链接计数(可能是性能),因此无法报告错误。有人能证实这个推理吗?@chris:很高兴知道这一点。但我的问题并不是关于vim;它可能是任何一个编辑。我在电视上看到了与Textmate相同的行为mac@nooblrnr:Textmate可能具有与Vim类似的文件处理:“取消链接,然后创建”、“创建临时文件,然后重命名”或“重命名,创建”等。。任何这些变化都会使您的日志进程写入旧文件(可能现在已取消链接),而编辑器写入的数据只会出现在新文件中(恰好与原始文件名具有相同的路径名)。@nooblrnr:请参阅和的POIX说明中的“如果一个或多个进程打开了文件”。inode链接计数和打开计数不相同。inode链接计数存在于磁盘上。开放计数存在内核内存中(或多或少)。在实际删除数据之前,它们都必须为零。如果链接计数为0且打开计数>0,则该文件为匿名且“私有”(如果打开计数>1,则为“共享”)。