xref: /wasmtime-44.0.1/examples/threads.rs (revision 9ce3ffe1)
1 //! This program is an example of how Wasmtime can be used with multithreaded
2 //! runtimes and how various types and structures can be shared across threads.
3 
4 // You can execute this example with `cargo run --example threads`
5 
6 use std::sync::Arc;
7 use std::thread;
8 use std::time;
9 use wasmtime::*;
10 
11 const N_THREADS: i32 = 10;
12 const N_REPS: i32 = 3;
13 
main() -> Result<()>14 fn main() -> Result<()> {
15     println!("Initializing...");
16 
17     // Initialize global per-process state. This state will be shared amongst all
18     // threads. Notably this includes the compiled module as well as a `Linker`,
19     // which contains all our host functions we want to define.
20     let engine = Engine::default();
21     let module = Module::from_file(&engine, "examples/threads.wat")?;
22     let mut linker = Linker::new(&engine);
23     linker.func_wrap("global", "hello", || {
24         println!("> Hello from {:?}", thread::current().id());
25     })?;
26     let linker = Arc::new(linker); // "finalize" the linker
27 
28     // Share this global state amongst a set of threads, each of which will
29     // create stores and execute instances.
30     let children = (0..N_THREADS)
31         .map(|_| {
32             let engine = engine.clone();
33             let module = module.clone();
34             let linker = linker.clone();
35             thread::spawn(move || {
36                 run(&engine, &module, &linker).expect("Success");
37             })
38         })
39         .collect::<Vec<_>>();
40 
41     for child in children {
42         child.join().unwrap();
43     }
44 
45     Ok(())
46 }
47 
run(engine: &Engine, module: &Module, linker: &Linker<()>) -> Result<()>48 fn run(engine: &Engine, module: &Module, linker: &Linker<()>) -> Result<()> {
49     // Each sub-thread we have starting out by instantiating the `module`
50     // provided into a fresh `Store`.
51     println!("Instantiating module...");
52     let mut store = Store::new(&engine, ());
53     let instance = linker.instantiate(&mut store, module)?;
54     let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
55 
56     println!("Executing...");
57     for _ in 0..N_REPS {
58         run.call(&mut store, ())?;
59         thread::sleep(time::Duration::from_millis(100));
60     }
61 
62     // Also note that that a `Store` can also move between threads:
63     println!("> Moving {:?} to a new thread", thread::current().id());
64     let child = thread::spawn(move || run.call(&mut store, ()));
65 
66     child.join().unwrap()?;
67 
68     Ok(())
69 }
70