如何在结构中更改Arc <u64>的值?

时间:2019-05-20 21:51:07

标签: rust

我无法在结构内部增加值。我遇到许多不同的编译错误。我对self的引用是一成不变的,我无法使其变得可变。

这是我的结构:

/// Proposer factory.
pub struct ProposerFactory<C, A>
where
    A: txpool::ChainApi,
{
    /// The client instance.
    pub client: Arc<C>,
    /// The transaction pool.
    pub transaction_pool: Arc<TransactionPool<A>>,
    /// The inherents pool
    pub inherents_pool: Arc<InherentsPool<<A::Block as BlockT>::Extrinsic>>,
    /// Current queue number
    cur_queue_no_ptr: Arc<u64>,
}

我想将cur_queue_no_ptr加+1

我尝试了以下代码:

let old_value_ref = Arc::get_mut(&mut self.cur_queue_no_ptr).unwrap();
let old_value = *old_value_ref;
let new_value = old_value + 1;

但出现此错误:

    152 |         let old_value_ref=Arc::get_mut(&mut self.cur_queue_no_ptr).unwrap();
        |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable

我尝试了以下代码:

let copied_arc = Arc::clone(&self.cur_queue_no_ptr);
let old_value = *Arc::make_mut(&mut copied_arc);
let new_value = old_value + 1;

另一个错误:

150 |         let old_value = *Arc::make_mut(&mut copied_arc);
    |                                        ^^^^^^^^^^^^^^^ cannot borrow as mutable

我也尝试过RefCell,但我得到了这个错误:

   ^^^^^ `std::cell::RefCell<u64>` cannot be shared between threads safely

显然,文档中的示例仅适用于变量,而不适用于结构,那么如何使用结构呢?

1 个答案:

答案 0 :(得分:4)

Arc仅允许在对Arc对象本身具有可变引用的情况下获得对内容的可变引用。

这里您想要的是RefCell的等价线程安全编码的等效项之一,即MutexRwLock。这些将在您借用内容时锁定对内容的访问,以便您可以安全地同时从多个线程访问它们:

// defining the counter variable
let counter = Arc::new(Mutex::new(0));

// lock the mutex to borrow
// it is automatically released when the borrow ends
let counter_lock = counter.lock();
*counter_lock = *counter_lock + 1;

Mutex仅允许您可变地借用,这使其更简单,但有时还不够。 RwLock还允许您不变地借用,这样您就可以拥有一个可变的借用或多个不变的借用。


或者,对于数字类型,最好使用atomic types。这些是专门为整数创建的,并且比MutexRwLock更快(因为它们不需要锁定任何东西,因此更改是原子发生的)。对于上述计数器,相应的示例如下:

// define the counter variable
let counter = Arc::new(AtomicU32::new(0));

// increment the counter
// no lock or mutable borrow is necessary
counter.fetch_add(1, Ordering::SeqCst);