Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
165 views
in Technique[技术] by (71.8m points)

multithreading - How do I box Arc and Mutexed variables?

The following code gets some variables in closures and returns a struct containing that data.

I can't return the struct with that data even when I box the struct and clone the variables; they are impossible to take out of this scope. I thought about using a callback closure but I don't really want to do that. Is there any way to take those out without having a callback?

pub fn get(addr: &str) -> std::io::Result<Box<Response>> {
    use std::sync::{Arc, Mutex};
    let mut crl = curl::easy::Easy::new();
    crl.url(format!("{}{}", API_ADDR, addr).as_str()).unwrap();

    // extract headers
    let headers: Vec<String> = Vec::with_capacity(10);
    let headers = Arc::new(Mutex::new(headers));
    {
        let headers = headers.clone();
        crl.header_function(move |h| {
            let mut headers = headers.lock().unwrap();
            (*headers).push(String::from_utf8_lossy(h).into_owned());
            true
        })
        .unwrap();
    }

    // extract body
    let body = Arc::new(Mutex::new(String::with_capacity(1024)));
    {
        let body = body.clone();
        crl.write_function(move |b| {
            let mut body = body.lock().unwrap();
            body.push_str(std::str::from_utf8(b).unwrap());
            Ok(b.len())
        })
        .unwrap();
    }
    crl.perform().unwrap();
    Ok(Box::new(Response {
        resp: body.lock().unwrap().clone(),
        headers: headers.lock().unwrap().clone(),
    }))
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The key error seems to be this one:

error[E0597]: `body` does not live long enough
  --> src/lib.rs:85:15
   |
85 |         resp: body.lock().unwrap().clone(),
   |               ^^^^ borrowed value does not live long enough
...
89 | }
   | - `body` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

The same for the headers object.

I was able to get a simplified reproducer of this by stubbing out a lot of your code:

use std::sync::{Arc, Mutex};

pub struct Response {
    resp: String,
    headers: Vec<String>,
}

pub fn get(addr: &str) -> std::io::Result<Box<Response>> {
    let headers: Vec<String> = Vec::with_capacity(10);
    let headers = Arc::new(Mutex::new(headers));
    let body = Arc::new(Mutex::new(String::with_capacity(1024)));
    Ok(Box::new(Response {
        resp: body.lock().unwrap().clone(),
        headers: headers.lock().unwrap().clone(),
    }))
}

I think this has to do with the lifetimes of the temporary variables constructed in the final Ok(Box::new(...)) return values.

I was able to get it to compile by pulling the lock/unwrap outside.

let body = body.lock().unwrap();
let headers = headers.lock().unwrap();
Ok(Box::new(Response {
    resp: body.clone(),
    headers: headers.clone(),
}))

From the fuller explaination given in Why do I get "does not live long enough" in a return value? I've found that you can write this as

return Ok(Box::new(Response {
    resp: body.lock().unwrap().clone(),
    headers: headers.lock().unwrap().clone(),
}));

i.e. adding an explicit return and a trailing semicolon. Though I have a feeling clippy might say that its bad style.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...