为什么不为包含 Arc 的结构实现 Send?

Why isnt Send implemented for a struct containing Arc?

我正在使用 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?

更新:

将结构定义替换为

pub struct Database{
    connection: Mutex<Client>
}

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

原因是特征实现 Send for Arc was defined as

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

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

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

不需要 Sync 实施。

Arc<T>允许多个线程同时访问同一个值Sync 特征是验证访问不会导致内存不安全的原因,因此 Arc 需要它。

另一方面,Mutex<T>通过锁定控制对T的访问,因此一次只有一个线程可以访问T(某种意义上,'sending' 它到具有锁的线程)。所以 Mutex<T>Sync 即使 T 不是(尽管它仍然必须是 Send)。

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