oneTBB icon indicating copy to clipboard operation
oneTBB copied to clipboard

Wasm. Workers die after completing first task

Open Alexufo opened this issue 6 months ago • 2 comments

Version of emscripten/emsdk: 3.1.74 tbb*: 2022.1.0 Multithread build.

We use tbb with emscripten. We create a pool of workers. We submit the first task and get the result in 0.7 s (multithreading works) Then all workers die and the next task runs on only one worker. 1.5 s (multithreading does not work)

Demo project https://github.com/Liahimz/MinimalWasm

https://github.com/emscripten-core/emscripten/issues/24412

Alexufo avatar May 26 '25 09:05 Alexufo

Thank you for reporting this issue, @Alexufo.

May I please clarify whether a "pool of workers" is referring to a TBB task arena and a "task" is referring to arena.execute([&]{tbb::parallel_for(...);}). If so, then do you see no multithreading with every single task after the first one?

Since there is no parallelism guarantee in TBB (https://oneapi-spec.uxlfoundation.org/specifications/oneapi/latest/elements/onetbb/source/task_scheduler.html), some of these parallel_for calls might execute entirely within the user thread, without involving the workers.

dnmokhov avatar May 27 '25 22:05 dnmokhov

Yes, that's correct. In our project, the process function launches parallel code like this:

arena.execute([&]{tbb::parallel_for(...);}).

After the first call to process, we encounter this error from the autogenerated wasm module:

wasm.js:9 main thread called exit(undefined): keepRuntimeAlive=false (counter=0),

and all web workers are terminated.

As a result, all subsequent calls to process run in single-threaded mode.

However, if we wrap calls to the process function in JS with a keep-alive mechanism, for example:


std::atomic<bool> keep_alive{false};

void idle_main_loop() {
  // No-op
}

EMSCRIPTEN_KEEPALIVE void start_keepalive_mainloop() {
  if (!keep_alive.exchange(true)) {
    emscripten_set_main_loop(idle_main_loop, 1, 1);
  }
}

EMSCRIPTEN_KEEPALIVE void stop_keepalive_mainloop() {
  if (keep_alive.exchange(false)) {
    emscripten_cancel_main_loop();
  }
}

…then we get this warning from the JS module: wasm.js:9 runtimeKeepalivePush -> counter=1, and the threads remain alive. With this approach, all subsequent calls to process run in parallel as expected.

Alexufo avatar May 28 '25 11:05 Alexufo