lseek / write突然返回-1,errno = 9(错误的文件描述符)

时间:2010-03-30 12:01:12

标签: c file-io handle seek

我的应用程序使用lseek()来寻找写入数据的所需位置。 使用open()成功打开了该文件,我的应用程序可以多次使用lseek()write()

在给定时间,对于某些用户而且不易重现,lseek()返回-1,errno为9.文件在此之前未关闭且文件句柄(int)未重置

在此之后,创建另一个文件; open()再次正常,lseek()write()再次有效。

更糟糕的是,该用户再次尝试了完整的序列,一切都很顺利。

所以我的问题是,操作系统可以出于某种原因为我关闭文件句柄吗? 什么可能导致这个?某种文件索引器或文件扫描程序?

解决这个问题的最佳方法是什么?这个伪代码是最好的解决方案吗? (不要介意代码布局,会为它创建函数)

int fd=open(...);
if (fd>-1) {
  long result = lseek(fd,....);
  if (result == -1 && errno==9) {
      close(fd..); //make sure we try to close nicely
      fd=open(...);

      result = lseek(fd,....);
  }
}

有人遇到类似的事情吗?

总结:文件搜索和写入对于给定的fd工作正常,并且在没有理由的情况下突然返回errno = 9。

4 个答案:

答案 0 :(得分:7)

  

所以我的问题是,操作系统可以出于某种原因为我关闭文件句柄吗?什么可能导致>这个?某种文件索引器或文件扫描程序?

不,这不会发生。

  

解决这个问题的最佳方法是什么?是   这个伪代码最好的解决方案?   (不要介意代码布局,会   为它创建函数)

不,最好的方法是找到错误并修复它。

  

有人遇到类似的事情吗?

我见过fds多次搞砸了,导致某些情况下的EBADF, 它在其他方面引人注目,它一直是:

  • 缓冲区溢出 - 溢出的东西并将一个无意义的值写入'int fd;'变量
  • 发生愚蠢的错误,因为有人做了一些角落案件 if(fd = foo[i].fd)当他们意为if(fd == foo[i].fd)
  • 线程之间的竞争条件,某些线程关闭了其他线程想要使用的错误文件描述符。

如果您可以找到重现此问题的方法,请在“strace”下运行您的程序,以便了解最新情况。

答案 1 :(得分:2)

操作系统不应随机关闭文件句柄(我假设是类Unix系统)。如果您的文件句柄已关闭,那么您的代码有问题,很可能在其他地方(感谢C语言和Unix API,这可能在代码中的任何位置,并且可能是由于,例如,轻微的缓冲溢出一段代码真的看起来像是无关的。)

你的伪代码是最糟糕的解决方案,因为它会给你一个修复问题的印象,而bug仍然潜伏着。

我建议您在打开和关闭文件或套接字的任何地方添加调试打印(即printf()调用)。另外,请尝试Valgrind

(我昨天刚刚有一个怪异的1个缓冲区溢出,它损坏了编译器生成的临时槽的最低有效字节以保存CPU寄存器;间接影响是另一个函数中的结构似乎被移动了几个字节。我花了很多时间来理解发生了什么,包括对Mips汇编代码的一些全面阅读。)

答案 2 :(得分:1)

我不知道你有什么类型的设置,但是下面的场景,我能想到产生这样的效果(或者类似的效果)。我没有对此进行测试以验证,所以请带上一粒盐。

如果要打开的文件/设备是作为服务器应用程序(例如NFS)实现的,请考虑服务器应用程序关闭/重新启动/重新启动时可能发生的情况。尽管最初在客户端有效的文件描述符可能不再映射到服务器端的有效文件句柄。这可以想象地导致一系列事件,其中客户将获得EBADF。

希望这有帮助。

答案 3 :(得分:0)

不,操作系统不应该像这样关闭文件句柄,而其他应用程序(文件扫描程序等)也不应该能够这样做。

不要解决问题,找到它的来源。如果您不知道问题的原因是什么,您永远不会知道您的解决方法是否 工作。

  1. 检查您的假设。在通话前errno是否设为0? fd在拨打电话时真的有效吗? (我知道你说过,但你检查吗?)
  2. 您平台上puts( strerror( 9 ) );的输出是什么?