5

我的应用程序用于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

4 回答 4

7

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

不,这不会发生。

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

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

有人有类似的经历吗?

我已经看到 fds 被搞砸了很多次,在某些情况下导致 EBADF,而在其他情况下则严重爆炸,它是:

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

如果您能找到重现此问题的方法,请在“strace”下运行您的程序,这样您就可以看到发生了什么。

于 2010-03-30T12:46:27.670 回答
2

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

您的伪代码是最糟糕的解决方案,因为它会给您一种已解决问题的印象,而错误仍然潜伏。

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

(我昨天刚刚发生了一个令人毛骨悚然的缓冲区溢出,它损坏了编译器为保存 CPU 寄存器而生成的临时槽的最低有效字节;间接影响是另一个函数中的结构似乎被移位了几个字节。我花了很长时间才理解发生了什么,包括彻底阅读 Mips 汇编代码)。

于 2010-03-30T12:13:34.737 回答
1

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

如果您打开的文件/设备实现为服务器应用程序(例如 NFS),请考虑如果服务器应用程序关闭/重新启动/重新启动会发生什么。文件描述符虽然最初在客户端有效,但可能不再映射到服务器端的有效文件句柄。这可能会导致一系列事件,其中客户端将获得 EBADF。

希望这可以帮助。

于 2010-03-30T12:47:36.893 回答
0

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

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

  1. 检查你的假设。调用前是否errno设置为0?fd 在通话时真的有效吗?(我知道你说的是,但你检查了吗?)
  2. 你平台上的输出是什么puts( strerror( 9 ) );
于 2010-03-30T12:30:43.637 回答