【问题标题】:C : Set timeout for blocking system calls [closed]C:为阻塞系统调用设置超时[关闭]
【发布时间】:2018-04-09 05:30:04
【问题描述】:

我有一个 C 代码,它使用对文件描述符的阻塞 I/O 调用,其中一些是磁盘 FD,所以我无法使用 select(),但有一些 I/O 调用 (read() / write() ) 被阻止了几秒钟。

如果系统调用阻塞超过指定的时间阈值,比如 500miliSec,是否可以中止系统调用并出错?

我不愿意使用非阻塞 I/O 调用,因为我正在记录 I/O 失败计数并在计数超过限制时终止进程,并且非阻塞 I/O 会迅速处理 I/O 错误计数超出阈值。

【问题讨论】:

  • 从磁盘块读取几秒钟?怎么会?这是由于数据量还是由于竞争访问?详细说明这可能有助于解决您的问题。
  • 我读对了吗,您对磁盘进行了一些读/写调用,并且它们占用了 500 毫秒以上的时间?因为这听起来像是与设置超时不同的问题......
  • 您仍然可以使用非阻塞 I/O。返回值应该类似于EAGAIN,因此您可以确保检查它并且在这种情况下不要增加错误计数器。
  • @Mikhail 这个问题与线程无关。
  • 在大多数 Unixy 系统上向大多数文件系统写入文件系统/磁盘是不可中断的。没有办法获得超时。信号不会中断read/write,非阻塞 I/O 不会做任何事情(如果你设法在 fd 上设置非阻塞,事情仍然会阻塞)。你运气不好。要么修复你的系统(因为等待磁盘 I/O 几秒钟听起来很糟糕),要么将写入磁盘的内容转移到某个单独的线程/进程并以这种方式管理超时。 (我在上面使用“大多数”,因为有例外,比如软 NFS 挂载或用户空间文件系统等)。

标签: c linux unix system-calls


【解决方案1】:

没有通用的方法来设置阻塞文件描述符的超时,但是如果您正在处理套接字,则可以使用套接字选项。

另一种方法是设置闹钟。这将在过期时引发一个信号,您可以使用该信号关闭套接字并生成必要的错误。

【讨论】:

  • 当 read() 在磁盘 I/O 上阻塞时,信号会中止调用并返回 errno 设置为某个值吗?还是我需要在信号处理程序中做一些事情来模仿上述内容?因为,我正在考虑为 500 毫秒设置一个 ualarm() 并进行 read() 调用并为 SIGALRM 声明一个空处理程序。
  • 你需要关闭 fd 解除阻塞然后返回。
【解决方案2】:

答案是特定于操作系统的,因为 C++ 不抽象线程终止。

请注意,函数只能通过中断机制在运行中被终止。在线程被TerminateThread 标记为删除后,经过一些微秒(由 NT 中断延迟命令控制),操作系统将获得对执行线程的 CPU 的控制权。实际上可能很难将其降低到 500 微秒,此外,延迟会因系统而异。请参阅 DPC 延迟和 DPC Latency Checker 等工具。

我还怀疑 IO 句柄会发生一些可怕的事情,这意味着对它们的后续命令可能会导致错误。

#include <thread>
#include <iostream>
#include <windows.h>
int main(int argc, char *argv[])
{
    auto thread_to_run_the_command_on = std::thread( [] {
        std::cout << "Started" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));// Your function goes here
        std::cout << "Never Called" << std::endl;
        // thread floats away into the aether, also RAII is violated for objects in this scope
        });
    //give it some time to start
    std::this_thread::sleep_for(std::chrono::seconds(3));
    const auto windows_native_thread_handle = thread_to_run_the_command_on.native_handle();
    TerminateThread(windows_native_thread_handle, 0);
    thread_to_run_the_command_on.detach();
}

【讨论】:

  • 据我所知,这个问题与线程无关。
  • @hyde 总而言之,这个家伙有一个调用某个库的函数,如果它花费的时间太长,则需要终止该函数。没有办法在不杀死线程的情况下杀死一个函数。
  • Windows 的 C++ 答案可能不是标记为 Unix 的 C 问题的最佳答案。
  • @alk 最初它被标记为 C++(这就是我找到它的方式)。但是,是的,猜测这家伙想要什么很难,我认为我们应该关闭它。
  • '500 微秒' OP 发布了 '500mSec'。这是模棱两可的,需要澄清。 500us 是内核信号超时的非常短的时间间隔,而轮询循环的时间则非常长。但是,对于基于内核的超时,500 毫秒很容易。
猜你喜欢
  • 2012-11-17
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 2010-12-26
  • 2013-11-16
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多