【问题标题】:Why isnt Send implemented for a struct containing Arc?为什么没有为包含 Arc 的结构实现 Send?
【发布时间】:2020-07-28 23:41:17
【问题描述】:

我正在使用a crate 与 Postgres 交互,只需手动编写 sql 查询(Diesel 似乎是我的简单案例),并且在多线程访问数据库客户端时遇到了困难。代码如下:

use postgres::Client;

pub struct Database{
    connection: Arc<Client>
}

impl Database {
    pub fn from_config(url: &str) -> Database {
        //...
    }
}

fn main() {
    let url: String = //...
    let db = db::Database::from_config(&url);
    let db_ref = Arc::new(db);
    consume(future(Arc::clone(&db_ref))); // <------------------- compile error
}

async fn future(db_ref: Arc<db::Database>){ }

fn consume<F>(f: F)
where F: Send{ }

postgres::Client 定义为

/// A synchronous PostgreSQL client.
pub struct Client {
    connection: Connection,
    client: tokio_postgres::Client,
}

编译这段代码时,我得到了一些疯狂的错误信息:

error[E0277]: `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)` cannot be shared between threads safely
  --> src/main.rs:17:5
   |
17 |     consume(future(Arc::clone(&db_ref)));
   |     ^^^^^^^ `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)` cannot be shared between threads safely
...
24 | fn consume<F>(f: F)
   |    ------- required by a bound in this
25 | where F: Send{ }
   |          ---- required by this bound in `consume`
   |
   = help: the trait `std::marker::Sync` is not implemented for `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)`
   = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>`
   = note: required because it appears within the type `std::boxed::Box<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>`
   = note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>>`
   = note: required because it appears within the type `postgres::connection::Connection`
   = note: required because it appears within the type `postgres::client::Client`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<postgres::client::Client>`
   = note: required because it appears within the type `db::Database`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<db::Database>`
   = note: required because it appears within the type `[static generator@src/main.rs:22:43: 22:46 db_ref:std::sync::Arc<db::Database> {}]`
   = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/main.rs:22:43: 22:46 db_ref:std::sync::Arc<db::Database> {}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`

这似乎意味着Database 没有实现Send。有没有办法实现Send?也许应该使用Mutex 或其他东西来代替Arc

UPD:

将结构定义替换为

pub struct Database{
    connection: Mutex<Client>
}

使错误消失,但完全不清楚为什么......

【问题讨论】:

    标签: multithreading rust traits


    【解决方案1】:

    Arc&lt;T&gt; 允许多个线程同时访问同一个值Sync trait 用于验证访问不会导致内存不安全,因此 Arc 需要它。

    另一方面,Mutex&lt;T&gt; 通过锁定控制对T 的访问,因此一次只有一个线程可以访问T(在某种意义上,将其“发送”给拥有锁定的线程) .所以Mutex&lt;T&gt;Sync,即使T 不是(尽管它仍然必须是Send)。

    但是Mutex&lt;T&gt; 本身并没有用,因为无论如何只有一个线程可以访问互斥锁。您通常将它与共享所有权的方式(即Arc)结合使用,以允许多个线程访问互斥锁。

    【讨论】:

      【解决方案2】:

      原因是 trait 实现 Send for Arc was defined as

      impl<T> Send for Arc<T>
      where
          T: Send + Sync + ?Sized, 
      

      所以Sync 也需要实现。这就是错误消息所说的。对于Mutex 依次为Send is defined

      impl<T: ?Sized + Send> Send for Mutex<T>
      

      不需要实现Sync

      【讨论】:

        猜你喜欢
        • 2021-02-23
        • 1970-01-01
        • 2020-03-24
        • 2018-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-07
        • 1970-01-01
        相关资源
        最近更新 更多