在actix-web路由功能中,我发现从互斥锁保护对象获取独立数据后,互斥锁必须处于锁定状态才能使用这些数据。如果互斥体仅在获取数据时加锁,则使用数据时会出现编译错误。下面是可以直接编译的代码:
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Mutex;
use async_trait::async_trait;
use actix_web::{web, App, HttpServer, HttpResponse, Result as ActixResult};
#[async_trait]
pub trait Reader: Send + Debug { }
#[derive(Clone, Debug)]
pub struct RemoteReader;
#[async_trait]
impl Reader for RemoteReader { }
#[derive(Default)]
pub struct DataReaders(HashMap<String, Box<dyn Reader>>);
impl DataReaders {
pub fn get_readers(&self, ids: &str) -> ActixResult<Vec<&dyn Reader>> {
let mut readers = Vec::new();
for id in ids.split(',') {
readers.push(self.0.get(id).unwrap().as_ref());
}
Ok(readers)
}
}
async fn get(data: web::Data<Mutex<DataReaders>>) -> ActixResult<HttpResponse> {
let mut readers = data.lock().unwrap().get_readers("1,2")?;
if readers.is_empty() {
return Ok(HttpResponse::NotFound().finish())
}
// Below will call multiple asynchronous functions, so I do not want to
// hold the lock of DataReaders for a long time.
readers.clear();
Ok(HttpResponse::Ok().finish())
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut readers = DataReaders{ 0: Default::default() };
readers.0.insert("1".to_string(), Box::new(RemoteReader{}));
readers.0.insert("2".to_string(), Box::new(RemoteReader{}));
let counter = web::Data::new(Mutex::new(readers));
HttpServer::new(move || {
App::new()
.app_data(counter.clone())
.route("/", web::get().to(get))
}).bind(("127.0.0.1", 8080))?.run().await
}
编译这段代码并得到错误:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:30:23
|
30 | let mut readers = data.lock().unwrap().get_readers("1,2")?;
| ^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
31 | if readers.is_empty() {
| ------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
我只想使用互斥锁来保护 HashMap,因为它会在其他路由函数中被更改。我认为从“get_readers”返回的 Vec<&dyn Reader> 对象不应受到保护,因为其中的所有项目都是只读的。那么我该如何解决这个问题呢?谢谢!
考虑一下如果另一条路线
HashMap
在此期间修改了会发生什么:&dyn Reader
您所持有的任何引用不仅会因您借用的特定地图项的任何修改而失效,还会因任何导致地图重新分配的插入而失效(实际上,即使是不相关的项目,任何突变HashMap
都会使您的参考无效,因为借用发生在整个地图的级别,而不是单个项目)。因此,除非您从 中移动/复制/克隆您正在使用的内容
HashMap
,否则Mutex
将需要保持锁定状态。因此,您可能会考虑将对象保存在引用计数分配中,例如Arc<dyn Reader>
而不是保存在Box
es 中,因为这些智能指针可以廉价地克隆,以便可以立即删除锁: