我有一个WriterJob
结构。它的功能并不重要;它所做的是产生一个长时间运行的任务,并为调用者提供一个API来检查作业的状态。
pub(crate) struct WriterJob {
...,
status: Status,
}
impl WriterJob {
async fn writer_job_impl(&mut self, rx: Receiver<WriteCommand>) {
// Job implementation details. It's important that `self` is mutuable
// since I update the job status
// eg.
// self.status = Status::Ready;
}
pub(crate) fn status(&self) -> Status {
self.status
}
pub(crate) fn spawn_writer_job(&mut self) -> Sender<WriteCommand> {
let (tx, rx) = mpsc::channel(10);
let handle = tokio::spawn(async move {
self.writer_job_impl(rx).await;
});
self.status = Status::Spawned;
tx
}
我得到这个错误:
error[E0521]: borrowed data escapes outside of associated function
--> src/io/buffered_write.rs:92:22
|
89 | pub(crate) fn spawn_writer_job(&mut self) -> Sender<WriteCommand> {
| ---------
| |
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
...
92 | let handle = tokio::spawn(async move {
| ______________________^
93 | | self.writer_job_impl(rx).await;
94 | | });
| | ^
| | |
| |__________`self` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
我想我理解编译器在抱怨它不知道self
是否会和派生的任务一样长,因此出现了生存期错误。但我不确定这是一个好的方法。一种可能性是使用Arc<Mutex<Status>>
或Arc<RwLock<Status>>
,但我不喜欢这种方法,因为我可能需要在self
中添加更多的可互操作字段。有没有更干净的方法来做到这一点?
2条答案
按热度按时间2hh7jdfx1#
你不能假设
self
在执行handle
的过程中没有被丢弃,这就是它抛出错误的原因。相反,您可以更改结构的设计,使其工作1.创建一个子结构,其中包含需要在线程之间共享的数据
1.创建对着色器数据执行操作的结构
另外,也许你可以用
tokio::sync::RwLock
代替时雄的互斥,如果很多线程都试图对数据执行不可变操作,这会更好,这样可以让很多线程读取数据而不会阻塞其他只读线程。1.最后一步是实现
WriteJob
函数,您可以使用&self
而不是&mut self
,因为您使用protected with mutex修改数据。41ik7eoe2#
一个可能的解决方案是使用内部可变性。通过将
Status
字段更改为Cell<Status>
(或原子类型,如coreband的crossbeam::atomic::AtomicCell
),可以删除mut
和生存期限制。假设您将
status
字段移动到内部类型中;我称之为WriterJobInner
。WriterJob
现在只拥有一个Arc<WriterJobInner>
:如果需要,可以为
WriterJob
实现Deref
,以简化某些访问。您的
WriterJob
实现现在将更改为:由于线程不需要传递
self
-既不是可变的,也不是不变的-错误就会消失。此外,由于status
现在是Cell
,因此也不需要mut self
。同样,您的
WriterJobInner
也只需要&self
:缺点是,
WriterJobInner
类型需要同时是Send
和Sync
,才能与Arc<T>
一起使用,但无论如何,您都要跨线程使用它。请注意,在创建线程后将
status
设置为Spawned
是一个争用条件。你可能想尝试原子地设置值,只有当它还没有被设置为其他值时。在这种方法中,最有用的组合可能是将需要一起更改的所有内容捆绑在一起,然后为其使用外部可变性。
使用上面的
RwLock
(或类似),例如如inner: Arc<RwLock<..>>
,要求您混合使用同步和异步代码(async
方法中的std::sync::RwLock
)或使您的访问器为async
(当使用tokio::sync::RwLock
时)。