从线程填充字符串缓冲区

时间:2017-03-11 01:05:40

标签: rust

使用hyper,我需要建立HTTP连接并读取结果。 我想把整个事情包裹起来, 所以我开始一个线程 并使用recv_timeout等待它。

仅包装send作品, 但我也要包裹read_to_string。 这是代码:

fn send_request(url: &str) -> Result<Response, MyAppError> {
    let mut c = Client::new();
    let mut req = c.get(url);
    req.send().map_err(|e| MyAppError::TcpError(e))
}

fn get_url(url: &str, mut buf: &mut String) -> Result<u16, MyAppError> {
    let mut resp = send_request(url)?;
    resp.read_to_string(&mut buf).map_err(|e| MyAppError::ReadError(e))?;
    Ok(resp.status.to_u16())
}

fn get_url_with_timeout_2(url: &str, mut buf: &mut String) -> Result<u16, MyAppError> {
    let (tx, rx) = mpsc::channel();
    let url = url.to_owned();
    let t = thread::spawn(move || {
        match tx.send(get_url(&url, &mut buf)) {
            Ok(()) => {} // everything good
            Err(_) => {} // we have been released, no biggie
        }
    });
    match rx.recv_timeout(Duration::from_millis(5000)) {
        Ok(resp) => resp,
        Err(_) => Err(MyAppError::Timeout),
    }
}

不幸的是我遇到了编译错误:

error[E0477]: the type `[closure@src/main.rs:53:25: 58:4 tx:std::sync::mpsc::Sender<std::result::Result<u16, MyAppError>>, url:std::string::String, buf:&mut std::string::String]` does not fulfill the required lifetime
  --> src/main.rs:53:11
   |
53 |   let t = thread::spawn(move || {
   |           ^^^^^^^^^^^^^
   |
   = note: type must outlive the static lifetime

如何将缓冲区传递给线程, 让它填补它, 然后在主线程上打印出缓冲区?

(这是Rust 1.15.1。)

This repository提供了完整的main.rs,并显示了获取网页的三个示例:

  1. 没有超时。

  2. 仅在send上暂停。

  3. 整个事情都超时。

  4. 如果你拿出3,它就会编译并运行。 我可以改变3来做这项工作吗?

    顺便说一句,提出网络请求实际上只是&#34;场合&#34;对于这个问题。我已经看过this question about doing a timeout了。我自己感兴趣的不是超时本身,而是关于如何在一个线程上填充缓冲区并在另一个线程上读取它。

    Share mutable object between threads建议使用ArcMutex在线程之间安全地共享数据。以下是对此的尝试:

    fn get_url_with_timeout_3(url: &str) -> Result<(u16, String), MyAppError> {
        let (tx, rx) = mpsc::channel();
        let url = url.to_owned();
        let shbuf = Arc::new(Mutex::new(String::new()));
        let shbuf2 = shbuf.clone();
        let t = thread::spawn(move || {
            let mut c = Client::new();
            let mut req = c.get(&url);
            let mut ret = match req.send() {
                Ok(mut resp) => {
                    let mut buf2 = shbuf2.lock().unwrap();
                    match resp.read_to_string(&mut buf2) {
                        Ok(_) => Ok(resp.status.to_u16()),
                        Err(e) => Err(MyAppError::ReadError(e)),
                    }
                }
                Err(e) => Err(MyAppError::TcpError(e)),
            };
    
            match tx.send(ret) {
                Ok(()) => {} // everything good
                Err(_) => {} // we have been released, no biggie
            }
        });
        match rx.recv_timeout(Duration::from_millis(5000)) {
            Ok(maybe_status_code) => {
                let buf2 = shbuf.lock().unwrap();
                Ok((maybe_status_code?, *buf2))
            }
            Err(_) => Err(MyAppError::Timeout),
        }
    }
    

    这为我提供了错误cannot move out of borrowed content,因为它试图返回*buf2(这是有道理的,因为它会从Mutex泄漏数据),但我不是确定如何在Rust可以看到模式的结构中表达这一点。

    如果请求线程超时,它会永久保持锁定 - 但我从不尝试读取缓冲区,所以谁在乎。如果请求线程完成,它将释放锁并消失,主线程将保留唯一的引用。我可以说它是安全的,但我不确定如何说服编译器。

    我不允许回答这个问题,因为它应该是重复的,但我已经使用评论中的想法为my GitHub repository添加了3个有效的实现。

0 个答案:

没有答案