ThreadCreator

Struct ThreadCreator 

Source
pub struct ThreadCreator { /* private fields */ }
Expand description

Handle for a dedicated Web Worker for dispatching new threads.

Please see below for example and how to avoid potential deadlocks.

§Example

Suppose your WASM package is built with wasm-pack using the following command:

wasm-pack build -t no-modules --out-dir ./pkg

which should produce pkg/your_package_bg.wasm and pkg/your_package.js.

Then you can create a ThreadCreator with:

use wasm_bindgen::prelude::*;
use wasm_bindgen_spawm::ThreadCreator;

let thread_creator = ThreadCreator::unready("pkg/your_package_bg.wasm", "pkg/your_package.js");
// on error, this is a JsValue error
assert!(thread_creator.is_ok());

§Dispatcher ready

Note that the function to create the Thread Creator is called unready rather than new. This is because the JS runtime may only start the dispatcher thread after the current execution context is finished. Blocking the thread before the ThreadCreator is ready may cause deadlocks.

For example, the following code will cause a deadlock, supposed there is a new function

use wasm_bindgen::prelude::*;
use wasm_bindgen_spawm::ThreadCreator;

pub fn will_deadlock() -> Result<(), Box<dyn std::error::Error>> {
    // the `new` function is hypothetical
    let thread_creator = ThreadCreator::new("pkg/your_package_bg.wasm", "pkg/your_package.js")?;
    // calling `spawn` is ok here
    let thread = thread_creator.spawn(move || {
        // do some work
    })?;
    // this will deadlock because the thread won't be spawned until this synchronous context is
    // finished
    thread.join()?;

    Ok(())   
}

The unready factory function exists to ensure user calls ready before start using the ThreadCreator to spawn threads. It also has a nice side effect that ThreadCreator is now Send + Sync since it doesn’t need to hold the Promise

use wasm_bindgen::prelude::*;
use wasm_bindgen_spawm::ThreadCreator;

pub async fn will_not_deadlock() -> Result<(), Box<dyn std::error::Error>> {
    let thread_creator = ThreadCreator::unready("pkg/your_package_bg.wasm", "pkg/your_package.js")?;
    let thread_creator = thread_creator.ready().await?;

    let thread = thread_creator.spawn(move || {
        return 42;
    })?;
    let value = thread.join()?;
    assert_eq!(value, 42);

    Ok(())   
}

Note that only ready requires await, and not spawn or join. This is because once the dispatcher is ready, shared memory is used for sending the spawn payload to the dispatcher instead of postMessage. This also means you only need this async step once when creating the ThreadCreator. You can write the rest of the code without async.

You can also disable the async feature and use into_promise_and_inner to avoid depending on wasm-bindgen-futures. You need to manually wait for the promise in this case before using the ThreadCreator (for example sending the promise to JS and awaiting it there). See the example below for more information.

§Joining threads

Joining should feel pretty much like the std library. However, there is one caveat - The main thread in Web cannot be blocked. This means in order to join a thread, you must run the WASM module in a Web Worker.

See JoinHandle for more information.

§Terminating

When the ThreadCreator is dropped, the dispatcher worker will be terminated. Threads that are spawn-ed but not started may start or not start, but threads that are already running are not impacted and can still be join-ed.

Generally you should avoid dropping the ThreadCreator until all spawned threads are joined. You can create a global thread creator by using thread_local:

use wasm_bindgen::prelude::*;
use wasm_bindgen_spawn::ThreadCreator;

thread_local! {
    static THREAD_CREATOR: OnceCell<ThreadCreator> = OnceCell::new();
}

#[wasm_bindgen]
pub fn create_thread_creator() -> Result<Promise, JsValue> {
    let thread_creator = ThreadCreator::unready("pkg/your_package_bg.wasm", "pkg/your_package.js")?;
    let (promise, thread_creator) = thread_creator.into_promise_and_inner();
    THREAD_CREATOR.with(move |tc| {
        tc.set(thread_creator);
    });
    Ok(promise)
    // the promise can then be awaited in JS (this is useful if the rest
    // of your code doesn't need wasm-bindgen-futures)
}


// On JS side, make sure this function is only called after the promise is resolved.
#[wasm_bindgen]
pub fn do_some_work_on_thread() {
    let handle = THREAD_CREATOR.with(|tc| {
        let tc = tc.get().unwrap();
        tc.spawn(move || {
            // do some work
        }).unwrap()
    });

    handle.join().unwrap();
}

Implementations§

Source§

impl ThreadCreator

Source

pub fn unready( wasm_url: &str, wbg_url: &str, ) -> Result<ThreadCreatorUnready, JsValue>

Create a Web Worker to dispatch threads with the wasm module url and the wasm_bindgen JS url. The Worker may not be ready until ready is awaited

See the struct documentation for more information

Source

pub fn spawn<F, T>(&self, f: F) -> Result<JoinHandle<T>, SpawnError>
where F: FnOnce() -> T + Send + 'static + UnwindSafe, T: Send + 'static,

Spawn a new thread to execute F.

Note that spawning new thread is very slow. Pool them if you can.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.