Closed Guillaume227 closed 1 year ago
You are entering a complex territory, since the support for threads in Webasm/emscripten is rather new and a bit experimental. I managed to get it working once, but I remember several steps had to be taken; and I do not remember all of them.
This note from https://emscripten.org/docs/porting/pthreads.html is especially important:
Browsers that have implemented and enabled SharedArrayBuffer, are gating it behind Cross Origin Opener Policy (COOP) and Cross Origin Embedder Policy (COEP) headers. Pthreads code will not work in deployed environment unless these headers are correctly set. For more information click this
This file is rather old, and I think you might be able to do it on a target level instead, using
if (EMSCRIPTEN)
target_compile_options(...)
Hi,
I made a test on my side.
Several things are required to be able to use threads with emscripten: see https://emscripten.org/docs/porting/pthreads.html
1/ The flag '-pthread` needs to be added to all files and at link time:
For example
add_compile_options(-pthread)
add_link_options(-pthread)
This can be done either with hello_imgui_emscripten_global_options.cmake or at the top of your main CMakeLists (before add_subdirectory(hello_imgui))
2/ In hello_imgui_cmake/emscripten/hello_imgui_emscripten.cmake , you may want to remove -s ALLOW_MEMORY_GROWTH=1
in order to suppress warnings about the fact the -s ALLOW_MEMORY_GROWTH combined with shared memory may be slow.
3/ When testing you need a server that sends COOP and COEP headers: see https://web.dev/coop-coep/
This simple python program can do it for you
#!/usr/bin/python3
# From https://gist.github.com/Faless/1e228325ced0662aee59dc92fa69efd7
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
import os, sys, logging
import argparse
class CORSRequestHandler (SimpleHTTPRequestHandler):
def end_headers (self):
self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
SimpleHTTPRequestHandler.end_headers(self)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--port', default=8060, type=int)
parser.add_argument('-r', '--root', default='', type=str)
args = parser.parse_args()
if args.root:
os.chdir(args.root)
test(CORSRequestHandler, HTTPServer, port=args.port)
Thanks, I am going to take a look. Let me point out the simplicity of the example project I referred to above. The compile step gave me great hopes in its simplicity. It is literaly just:
subprocess.check_call(
[
"em++",
"-std=c++17",
"-pthread",
"-s",
"PTHREAD_POOL_SIZE=2",
"-s",
"ENVIRONMENT=web,worker",
"main.cc",
"-o",
"index.html",
]
It works for me in the same exact setup (trying both up-to-date vanilla Chrome and Firefox) that I am playing with hello_imgui
in, so it feels tantalizingly close.
From what I can tell that example also does not make use of COEP / COOP. EDIT: Never mind, it does use COEP/COOP.
Finding where to plug that in my hello_imgui
dummy std::thread example is proving harder than I thought.
I am going to make another attempt with the pointers you gave me.
Thanks so much, pointing out that COOP/COEP saved the day for me. I had tunnel vision on the Cmake / C++ / em++ settings and overlooked that initially! Do you want a PR for this so other people get it right the first time? or is that use case out of scope for a minimal hello_imgui use case?
Regarding ALLOW_MEMORY_GROWTH: are you saying that in your experience that warning is a false positive and should be turned off or is it warning about a real performance impact, in the context of emscripten-wrapped multi-threaded cpp ?
Actually I don’t know
Do you want a PR for this so other people get it right the first time? or is that use case out of scope for a minimal hello_imgui use case?
This would be an interesting addition, which I am considering to work on.
However, it would need to be well documented and sufficiently customizable, i.e.
If you feel like working on it, tell me ;-)
I am just looking for an opportunity to give back. In that case it looks like you have fleshed it out pretty well in your mind already and my added value would be limited.
In that case it looks like you have fleshed it out pretty well in your mind already and my added value would be limited.
Agreed 👍
I added support for multi-threading in b9e81983294cb27d085a7e600a6067df06b5fdb9.
I also added some doc about the usage in the main CMakeLists.txt
:
I would like to start experimenting with an emscripten build of my app (that was part of the original draw to hello_imgui as I was able to bring up the minimal example
hello_imgui_app
on a localhost server so quickly). My imgui application usesstd::thread
and my understanding is I need to turn on a number of additional compilation flags like-pthread
and-sASYNCIFY
. I am struggling to find where these should go in the currenthello_imgui
setup.I see the following comment in
hello_imgui_emscripten.cmake
:Is the idea to add something like
in hello_imgui_emscripten_global_options.cmake ?
I can't seem to marry the settings working on e.g. this sample emscripten with threads project : https://github.com/jiulongw/emscripten-mutex-test/blob/main/run to the
hello_imgui
cmake framework.The minimal example I am working with is:
It compiles but doesn't display anything in the browser (if I comment out the thread line, it's basically the
hello_imgui_app
and it works).