Mario Carneiro
Mario Carneiro

Reputation: 1693

Using thread unsafe values in an async block

In this code snippet (playground link), we have some simple communication between two threads. The main thread (which executes the second async block) sends 2 to thread 2 in the async move block, which receives it, adds its own value, and sends the result back over another channel to the main thread, which prints the value.

Thread 2 contains some local state, the thread_unsafe variable, which is neither Send nor Sync, and is maintained across an .await. Therefore the impl Future object that we are creating is itself neither Send nor Sync, and hence the call to pool.spawn_ok is a compile error.

However, this seems like it should be fine. I understand why spawn_ok() can't accept a future that is not Send, and I also understand why the compilation of the async block into a state machine results in a struct that contains a non-Send value, but in this example the only thing I want to send to the other thread is recv and send2. How do I express that the future should switch to non-thread safe mode only after it has been sent?

use std::rc::Rc;
use std::cell::RefCell;
use futures::channel::oneshot::channel;
use futures::executor::{ThreadPool, block_on};

fn main() {
    let pool = ThreadPool::new().unwrap();
    let (send, recv) = channel();
    let (send2, recv2) = channel();
    pool.spawn_ok(async move {
        let thread_unsafe = Rc::new(RefCell::new(40));
        let a = recv.await.unwrap();
        send2.send(a + *thread_unsafe.borrow()).unwrap();
    });
    let r = block_on(async {
        send.send(2).unwrap();
        recv2.await.unwrap()
    });
    println!("the answer is {}", r)
}

Upvotes: 1

Views: 340

Answers (1)

user4815162342
user4815162342

Reputation: 155216

but in this example the only thing I want to send to the other thread is recv and send2

There is also the local variable thread_unsafe which is used across an .await. Since .await can suspend an async function, and later resume it on another thread, this could send thread_unsafe to a different thread, which is not allowed.

Upvotes: 2

Related Questions