Rust 当它';它掉下来了?

Rust 当它';它掉下来了?,rust,Rust,我在一个被多次克隆的结构中有一个Arc字段。它在并发线程之间共享Drop::Drop在每个克隆超出范围时调用。有没有办法确定最后一个(唯一的)Arc何时调用Drop::Drop 很明显,强计数受到数据竞争的影响(我见过)。因此,您不能指望Arc::strong_count()==1(没有双关语) 我发现由于移动问题,无法使用Arc::try_unwrap() Arc::is_unique()是私有的 除了保留一个Arc字段,该字段在克隆时递增,在删除时递减,还有什么方法可以确定drop

我在一个被多次克隆的结构中有一个
Arc
字段。它在并发线程之间共享
Drop::Drop
在每个克隆超出范围时调用。有没有办法确定最后一个(唯一的)
Arc
何时调用
Drop::Drop

  • 很明显,强计数受到数据竞争的影响(我见过)。因此,您不能指望Arc::strong_count()==1(没有双关语)

  • 我发现由于移动问题,无法使用
    Arc::try_unwrap()

  • Arc::is_unique()
    是私有的

除了保留一个
Arc
字段,该字段在克隆时递增,在删除时递减,还有什么方法可以确定
drop
是否用于唯一的
Arc

这是一个MRE:

use std::sync::{Arc};

#[derive(Debug)]
enum Action {
    One, Two, Three
}

// Thing trait which operates on an Action, which should be a enum, allowing for
// different action sets.
trait Thing<T> {
    fn disconnected(&self);
    fn action(&self, action: T);
}

// There are many instances of an ActionController.
// There may be zero or more clones of an instance.
// The final drop of the instances should call thing.disconnected()
// In a multi-core environment, the same instance may be running on multiple cores
// ActionController should not be generic.
#[derive(Clone)]
struct ActionController {
    id: usize,
    thing: Arc<dyn Thing<Action>>,
}
impl ActionController {
    fn new(id: usize, thing: Box<dyn Thing<Action>>) -> Self {
        Self { id, thing: Arc::from(thing) }
    }
    fn invoke(&self, action: Action) {
        self.thing.action(action);
    }
}

//
// To work around the drop issue, I've implemented Clone for ActionController which
// performs a fetch_add(1) on clone and a fetch_sub(1) on drop. This provides
// suficient information to call disconnected() -- but it just seems like there's
// got to be a better way.
impl Drop for ActionController {
    fn drop(&mut self) {
        // drop will be called for each clone of an Controller instance. When
        // the unique instance is dropped, disconnected() must be called
        self.thing.disconnected();
    }
}

struct Controlled {}
impl Thing<Action> for Controlled {
    fn disconnected(&self) { println!("disconnected")}
    fn action(&self, action: Action) {println!("action: {:#?}", action)}
}

fn bad() {
    let controlled = Controlled{};
    let controlled = Box::new(controlled) as Box<dyn Thing<Action>>;
    let controller = ActionController::new(1, controlled);
    let clone = controller.clone();
    controller.invoke(Action::One);
    clone.invoke(Action::Two);
    drop (controller);
    clone.invoke(Action::Three);
}

fn main() {
    bad();
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn incorrect() {
        bad();
    }
}
使用std::sync::{Arc};
#[导出(调试)]
枚举操作{
一,二,三
}
//操作一个动作的东西特性,应该是枚举,允许
//不同的动作集。
特质事物{
fn已断开连接(&self);
fn动作(和自我,动作:T);
}
//ActionController有许多实例。
//一个实例可能有零个或多个克隆。
//实例的最后一次删除应该调用thing.disconnected()
//在多核环境中,同一实例可能运行在多个核上
//ActionController不应为泛型。
#[衍生(克隆)]
结构动作控制器{
id:使用,
事情:Arc,
}
impl操作控制器{
fn新(id:usize,thing:Box)->Self{
Self{id,thing:Arc::from(thing)}
}
fn调用(&self,操作:操作){
自我。事物。行动(行动);
}
}
//
//为了解决drop问题,我已经为ActionController实现了Clone
//对克隆执行fetch_add(1),对drop执行fetch_sub(1)。这就提供了
//有足够的信息来调用disconnected()--但似乎有
//一定是个更好的方法。
ActionController的impl Drop{
fn下降(&mut自我){
//将为控制器实例的每个克隆调用drop
//已删除唯一实例,必须调用disconnected()
self.thing.disconnected();
}
}
结构控制{}
为受控制的对象执行命令{
fn断开连接(&self){println!(“断开连接”)}
fn action(&self,action:action){println!(“action:{:},action)}
}
fn bad(){
设受控=受控{};
让受控=框::新(受控)为框;
让控制器=动作控制器::新建(1,受控);
让clone=controller.clone();
调用(Action::One);
调用(Action::Two);
下降(控制器);
clone.invoke(操作::三);
}
fn main(){
坏的();
}
#[cfg(测试)]
模试验{
使用超级::*;
#[测试]
fn不正确(){
坏的();
}
}

如果没有stdlib支持,我认为没有任何完美的方法可以做到这一点(退出
Arc::drop

弱::强计数
弱::升级
受种族影响较小,因此如果您
降级
您的Arc,然后将其丢弃,如果weakref的强计数为0或尝试
升级
失败,您知道
Arc
已死亡,但无法保证当前线程将其杀死,两人可能同时删除了
,然后才有时间检查weakref的强计数


我认为唯一的防弹方法是通过存储在
Arc
内的
下降
得到通知,保证只调用您一次。

Arc::try_unwrap可能是实现此目的的理想方法-是否可以重新构造代码以避免您遇到的移动问题?

您为什么想知道?如果在删除
互斥体之前需要执行一些额外的清理代码,可能可以使用
Arc
,其中
MyLockedThing
是一个包含
Mutex
的结构,它执行
Drop
来进行清理?

似乎希望在删除
弧中的数据时收到通知。如果是这样,可以通过在
的“内部”类型上执行
Drop

定义新类型:

struct ThingAction(Box<dyn Thing<Action>>);

impl Thing<Action> for ThingAction {
    fn disconnected(&self) {
        self.0.disconnected()
    }
    
    fn action(&self, action: Action) {
        self.0.action(action)
    }
}
然后使用新类型:

#[derive(Clone)]
struct ActionController {
    id: usize,
    thing: Arc<ThingAction>,
}
impl ActionController {
    fn new(id: usize, thing: Box<dyn Thing<Action>>) -> Self {
        Self { id, thing: Arc::new(ThingAction(thing)) }
    }
#[派生(克隆)]
结构动作控制器{
id:使用,
事情:Arc,
}
impl操作控制器{
fn新(id:usize,thing:Box)->Self{
Self{id,thing:Arc::new(ThingAction(thing))}
}

可能会存储一个
东西:选项
,并在下拉菜单中执行
Arc::try_unwrap(thing.take())
strong\u count
如果使用不当,会受到竞争的影响,但不是通常使用的数据竞争。安全生锈是无数据竞争的。如果
Thing
的丢弃行为取决于de>Arc
它存储在中,您可能正在做一些非常不寻常的事情。很难回答您的问题,因为它不包括一个。我们无法说出是什么板条箱(及其版本),类型、特征、字段等都出现在代码中。如果您试图在上重现错误,我们将更容易帮助您。如果可能的话,在全新的货运项目中,则您的问题将包括其他信息。您可以使用这些信息来减少您在此处发布的原始代码。谢谢!我认为这将有助于c明确你想要什么。什么代码需要知道何时调用
drop
?它需要在调用之前或之后知道吗?示例代码将非常有用。MRE是一个挑战,因为它有点复杂,涉及到同事。让我来处理它,因为它可能会产生一些有趣的模式。如果我降级一个唯一的,它将变得非常有趣这样就再也听不到了,不是吗
#[derive(Clone)]
struct ActionController {
    id: usize,
    thing: Arc<ThingAction>,
}
impl ActionController {
    fn new(id: usize, thing: Box<dyn Thing<Action>>) -> Self {
        Self { id, thing: Arc::new(ThingAction(thing)) }
    }