Qt WebAssemblyをマルチスレッドに対応させる

# はじめに
こちらの記事で構築した環境を元にQtのWebAssemblyをマルチスレッド対応にしていきます。

https://qiita.com/AlohaYos/items/0fecff0840277eae4a8a

# QtのマルチスレッドWebAssembly

オンラインインストール版など配布版のQt5に付属しているのはシングルスレッド版のWebAssemblyです。本家Qtサイトの説明を読むと「なるべく多くの種類のブラウザに対応するためにシンプルな造りにしている」そうです。マルチスレッド動作するプロジェクトを動作させるためには、マルチスレッド版のWebAssemblyが必要になります。そのためには配布版のQtは使用できず、Qt5をソースファイルからマルチスレッド・オプションを付加してビルドして利用しなければなりません。

## Qtソース取得

    mkdir ~/qt5-build
    cd ~/qt5-build
    git clone git://code.qt.io/qt/qt5.git
    cd qt5
    git checkout 5.15
    git submodule update --init –recursive

## ビルド
私の環境ではmakeに3時間ほどかかりました。

    mkdir build
    cd build
    touch .qmake.stash
    touch .qmake.super
    source $EMSDK/emsdk_env.sh
    ../qt5/configure -xplatform wasm-emscripten -feature-thread -developer-build -opensource -static -nomake examples -nomake tests -no-dbus -no-headersclean -system-libpng -no-ssl -no-warnings-are-errors -skip qtlocation -skip qt3d -skip qtwebengine -prefix $PWD/qtbase
    make

## ファイルのコピー
シングルスレッド版Qtと並べてマルチスレッド版Qt一式を配置します。
（私の環境ではシングルスレッド版は/opt/Qt/5.15.5にあります）

    sudo mkdir /opt/Qt/5.15.3/wasm_multithread
    sudo cp -r ~/qt5-build/build/qtbase/* /opt/Qt/5.15.3/wasm_multithread/

## Kitの作成

Qt Creatorの「ツール」→「オプション」メニューを開き、「Kits」ページの「Qtバージョン」タブを表示。
「追加」ボタンを押して、/opt/Qt/5.15.3/wasm_multithread/qbase/bin/qmakeを選択します。
![名称未設定10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/b98daaa6-b6df-8d3b-3c39-d0cc951b8541.png)
「Kits」タブを表示して「Add」ボタンを押し、下記のようにフィールドを設定。
「名前:」フィールドを「Qt %{Qt:Version} WebAssembly MultiThread」
「Qt version:」フィールドを「Qt5.15.3」
![名称未設定11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/656857d6-16aa-dfa5-b292-d402d2cab6e5.png)

## Qtプロジェクトの設定
Qt Creatorプロジェクト設定画面で、マルチスレッド用のKitを使ってBuild&Runを設定します。
![Screenshot from 2021-08-05 09-53-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/29360522-14e8-4bf7-fe57-5b13cddf0ddb.png)

![Screenshot from 2021-08-05 09-54-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/277051a1-3e43-55e8-d188-3efd84b0b5bb.png)

## プロジェクトファイル(.pro)の設定
マルチスレッドプロジェクトのEmscriptenビルドオプションとして次の２つがあります。

    QMAKE_WASM_PTHREAD_POOL_SIZE = 4
    QMAKE_WASM_TOTAL_MEMORY = 1GB

![スクリーンショット 2021-08-05 10.13.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/002c81b2-17a2-1081-41ca-91884c93999f.png)
QMAKE_WASM_PTHREAD_POOL_SIZEはブラウザVMに準備させるスレッド数（WebWorker）で、EmscriptenのPTHREAD_POOL_SIZEオプションにマップされます。
また、マルチスレッドでは実行時にヒープ領域の拡大が許されていないので、アプリのビルド時にヒープメモリサイズを指定する必要があります。その値がQMAKE_WASM_TOTAL_MEMORYで、EmscriptenのTOTAL_MEMORYオプションにマップされます。

これらの設定値が大きすぎるとビルドやランができなくなります。
私の環境ではPTHREAD_POOL_SIZE=15にするとChromeでのアプリ起動ができなくなりました。main関数にブレークポイントを設置しても、その前にアボートするのでWebWorkerを生成する段階でリソースが枯渇しているのかもしれません。PTHREAD_POOL_SIZE=14に変更するとmain関数に到達しました。
またQMAKE_WASM_TOTAL_MEMORY=4GBでビルドエラーになり、3GBではOKでした。
これらはOSやブラウザの設定で変動するのかもしれませんが、詳しい情報は得られていません。

さらに詳しくはQt WebAssembly本家サイトやEmscriptenサイトの情報を調べてみてください。

https://wiki.qt.io/Qt_for_WebAssembly

https://emscripten.org/docs/porting/pthreads.html

## マルチスレッド実行
マルチスレッドアプリをChromeで実行すると、PTHREAD_POOL_SIZEで指定した数だけスレッドが準備されていることが分かります（MultiThreadSample.worker.js）。
![Screenshot from 2021-08-05 10-12-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1839672/387d751f-f11c-bd98-4b34-3d3fb38e4378.png)

# ブラウザのマルチスレッド設定

私が使っているChromeは下記バージョンですが、マルチスレッドWebAssemblyに対応しているので設定変更は不要です。そのままで実行できます。

    Google Chrome バージョン: 91.0.4472.114（Official Build） （64 ビット）

Firefoxは79からサポートされているようです。それ以前のSharedArrayBufferを無効化されているFirefoxではマルチスレッドが動きませんが、アドレスバーに about:configと入力して、javascript.options.shared_memoryの値を有効にすれば動作するらしいです。

# 参考サイト

https://wiki.qt.io/Qt_for_WebAssembly

https://www.qt.io/blog/2019/06/26/qt-webassembly-multithreading

https://emscripten.org/docs/porting/pthreads.html

https://github.com/WebAssembly