Io 如何处理长时间运行的外部函数调用,如在Rust中阻塞I/O?

Io 如何处理长时间运行的外部函数调用,如在Rust中阻塞I/O?,io,task,ffi,rust,Io,Task,Ffi,Rust,编者按:这个问题来自Rust 1.0之前的版本,使用了Rust 1.0代码中不存在的术语和函数。所表达的概念仍然相关 我需要在我的Rust程序中通过POSIX文件描述符读取外部进程提供的数据。文件描述符连接保持了很长的时间(小时),另一端不时地向我传递数据。我需要不断地读取和处理数据流 为此,我编写了一个循环,调用libc::read()(readv)来读取数据,并在收到数据时进行处理。因为这会阻塞整个调度程序,所以我正在一个新的调度程序上生成一个任务(task::spawn\u sched(S

编者按:这个问题来自Rust 1.0之前的版本,使用了Rust 1.0代码中不存在的术语和函数。所表达的概念仍然相关

我需要在我的Rust程序中通过POSIX文件描述符读取外部进程提供的数据。文件描述符连接保持了很长的时间(小时),另一端不时地向我传递数据。我需要不断地读取和处理数据流

为此,我编写了一个循环,调用
libc::read()
readv
)来读取数据,并在收到数据时进行处理。因为这会阻塞整个调度程序,所以我正在一个新的调度程序上生成一个任务(
task::spawn\u sched(SingleThreaded)
)。只要它运行,就可以正常工作,但我找不到一种方法来彻底关闭循环

由于循环大部分时间处于阻塞状态,因此我无法使用端口/通道通知循环退出

我试图通过使用一个失败的链接任务来终止循环任务(在监督下生成循环任务,在其中生成一个链接任务,并在
失败之前等待端口上的信号发生)(
使用它来终止循环任务)。它在测试中运行良好,但不会中断
libc::read()
(任务在读取完成之前不会失败,并且在某个时间会命中
task::yield()

通过查看libcore源代码,我学到了很多,但似乎找不到合适的解决方案

  • 有没有一种方法可以杀死Rust中的一个(子)任务,即使它正在执行一些长的外部函数调用,比如阻塞读取
  • 有没有办法在POSIX文件描述符上执行非阻塞读取,以便Rust能够控制任务
  • 如果用户终止我的程序,我如何对信号做出反应,例如
    SIGTERM
    ?Rust中似乎还没有类似
    sigaction()
    的东西
  • 根据我们的研究,杀死一个任务是不可能的,就目前而言,更不用说阻止读取了
  • mozilla/rust/pull/11410
    之后可以这样做,另请参阅我的其他问题报告,了解rust zmq
    erickt/rust zmq/issues/24
    ,这也取决于此。(很抱歉链接)
  • 也许这个方法对你有用
  • 有没有一种方法可以杀死Rust中的一个(子)任务,即使它正在执行一些长的外部函数调用,比如阻塞读取

    没有

    另见:

    有没有一种方法可以进行非阻塞读取[…],从而使Rust能够控制任务

    另见:

    在POSIX文件描述符上

    另见:

    我如何对信号作出反应

    确定所需的平台支持,然后选择合适的板条箱

    另见:

    把它们放在一起 另一个终端

    printf'hello\nthere\nworld'>/tmp/testpipe
    kill-s usr1$PID\u进程的\u
    
    目前似乎不可能做到这一点,但仍在努力改进异步I/O:Rust 1.0中现在是否有任何关于非阻塞I/O的更新?这一评论要晚很多,但由于这个问题没有公认的答案,我将其放在这里:自1.0以来,io故事发生了很大的变化。目前,人们非常关注asyn使用mio的c i/o,基于linux和windows的内核库(一时记不起来)。可能很快就会有一些语法级别的功能。更一般地说,如果工作线程有一个工作循环,此循环可以检查关机消息。如果它在i/o上被阻止,我不知道是否可以唤醒它。我想了解更多有关这方面的信息。
    use future::Either;
    use signal_hook::iterator::Signals;
    use std::os::unix::io::FromRawFd;
    use tokio::{fs::File, io, prelude::*};
    
    type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
    
    fn main() -> Result<()> {
        let signals = Signals::new(&[signal_hook::SIGUSR1])?;
        let signals = signals.into_async()?;
    
        let input = unsafe { std::fs::File::from_raw_fd(5) };
        let input = File::from_std(input);
        let lines = io::lines(std::io::BufReader::new(input));
    
        let signals = signals.map(Either::A);
        let lines = lines.map(Either::B);
    
        let combined = signals.select(lines);
    
        tokio::run({
            combined
                .map_err(|e| panic!("Early error: {}", e))
                .for_each(|v| match v {
                    Either::A(signal) => {
                        println!("Got signal: {:?}", signal);
                        Err(())
                    }
                    Either::B(data) => {
                        println!("Got data: {:?}", data);
                        Ok(())
                    }
                })
        });
    
        Ok(())
    }
    
    [package]
    name = "future_example"
    version = "0.1.0"
    authors = ["An Devloper <an.devloper@example.com>"]
    edition = "2018"
    
    [dependencies]
    tokio = "0.1.22"
    signal-hook = { version = "0.1.9", features = ["tokio-support"] }