【问题标题】:EAGAIN on a blocking read system call on regular fileEAGAIN 对常规文件的阻塞读取系统调用
【发布时间】:2018-08-08 06:46:04
【问题描述】:

所以,这是一个奇怪的案例,我有时会看到但无法找出原因。

我们有一个从常规文件中读取的 C 程序。还有其他进程写入同一个文件。该应用程序基于这样一个事实,即在 Linux 中写入是原子的,写入大小可达 4096 字节。

文件未使用非阻塞标志打开,所以我的假设是读取会阻塞。

但有时在启动过程中,我们会在errno 中看到“资源暂时不可用”错误。以及 read != -1 返回的大小,但部分读取的大小。

错误消息类似于:

2018-08-07T06:40:52.991141Z,无效的消息大小,log_s.bin,fd 670,资源暂时不可用,读取大小 285,预期大小 525

我的问题是:

  1. 为什么我们在阻止文件读取时收到EAGAIN

  2. 为什么返回值不是-1?

  3. 这只发生在它启动的初始时间。此后它工作正常。有哪些极端情况会让我们陷入这种情况?

【问题讨论】:

  • 当它启动时,它没有任何数据要读取,所以 read 正在等待数据读取,read 被阻塞,这就是你得到 EAGAIN 的原因。
  • 如果说写是原子的,那为什么还要等待呢?上述错误消息的所有 525 个字节应该都可用,对吧?
  • 你读取的文件存放在哪种文件系统中?

标签: c linux input posix errno


【解决方案1】:

为什么我们在阻止文件读取时得到 EAGAIN?

你不是(见下文)。

为什么返回值不是-1?

因为操作没有失败。

如果对read() 的调用失败,则errno only 的值具有合理的值。当且仅当返回 -1 时,对 read() 的调用才会失败。

来自Linux man-page for read()

返回值

成功时,返回读取的字节数(零表示结束 文件),并且文件位置由这个数字提前。它是 如果此数字小于字节数,则不是错误 请求;

[...]

出错时返回-1,并适当设置errno

read() 的常见模式是

char buffer[BUFFER_MAX];
char * p = buffer;
size_t to_read = ... /* not larger then BUFFER_MAX! */

while (to_read > 0)
{
  ssize_t result = read(..., p, to_read);
  if (-1 == result)
  {
    if (EAGAIN == errno || EWOULDBLOCK == errno)
    {
      continue;
    }

    if (EINTR == errno)
    {
      continue; /* or break depending on application design. */
    }

    perror("read() failed");

    exit(EXIT_FAILURE);
  }
  else if (0 < result)
  {
    to_read -= (size_t) result;
    p += (size_t) result;
  }
  else if (0 == result) /* end of file  /  connection shut down for reading */
  {
    break;
  }
  else
  {
    fprintf(stderr, "read() returned the unexpected value of %zd. You probably hit a (kernel) bug ... :-/\n", result);

    exit(EXIT_FAILURE);
  }
}

If (0 < to_read)
{
  fprintf(stderr, "Encountered early end of stream. %zu bytes not read.\n", to_read);
}

【讨论】:

  • 是的,当然;不错!
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 2020-09-14
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-02-18
  • 1970-01-01
相关资源
最近更新 更多