Emscripten 中的“Module”变量机制,同时将 Pthread 编译为 worker
Posted
技术标签:
【中文标题】Emscripten 中的“Module”变量机制,同时将 Pthread 编译为 worker【英文标题】:The `Module` variable's mechanism in Emscripten while compiling Pthread to workers 【发布时间】:2020-09-02 03:35:44 【问题描述】:在将 Pthread 编译为 Web Worker + Wasm 时,我对 Emsripten 中的 Module
变量感到困惑
有一个简单的 Pthread 代码,它只是在每个线程的共享变量 sum
中添加 1
。 (最后附上simple.c
。)
我们可以使用命令编译Pthread代码:
$ emcc simple.c -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 -o simple.html
Emscripten 将生成 simple.html
、simple.js
、simple.worker.js
和 simple.wasm
。
在simple.worker.js
,有一个sn-p:
// simple.worker.js
var Module = ;
// ...
Module['instantiateWasm'] = function(info, receiveInstance)
// Instantiate from the module posted from the main thread.
// We can just use sync instantiation in the worker.
var instance = new WebAssembly.Instance(Module['wasmModule'], info);
// We don't need the module anymore; new threads will be spawned from the main thread.
Module['wasmModule'] = null;
receiveInstance(instance); // The second 'module' parameter is intentionally null here, we don't need to keep a ref to the Module object from here.
return instance.exports;
;
注意它在worker中声明了var Module =
,并定义了Module['instantiateWasm']
。
但是,Module['instantiateWasm']
只被simple.js
调用,代码 sn-p 如下:
//simple.js
var Module =
// ...
if (Module['instantiateWasm'])
try
var exports = Module['instantiateWasm'](info, receiveInstance);
return exports;
catch(e)
err('Module.instantiateWasm callback failed with error: ' + e);
return false;
// ...
我们可以看到,simple.js
也声明了var Module =
。
AFAIK,VAR
全局变量无法通过主线程及其工作线程访问。 我不明白为什么simple.js
可以调用Module['instantiateWasm']
作为simple.js
的Module
和simple.worker.js
的Module
应该不是一回事。
线程代码:
// simple.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUMTHRDS 4
#define MAGNIFICATION 1e9
typedef struct
int thread_id;
double *sum;
Arg;
pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;
void *count_pi(void *arg)
Arg *data = (Arg *)arg;
int thread_id = data->thread_id;
double *sum = data->sum;
pthread_mutex_lock(&mutexsum);
*sum += 1;
pthread_mutex_unlock(&mutexsum);
printf("Thread %d: sum=%f\n", thread_id, *sum);
pthread_exit((void *)0);
int main(int argc, char *argv[])
pthread_mutex_init(&mutexsum, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
double *sum = malloc(sizeof(*sum));
*sum = 0;
Arg arg[NUMTHRDS];
for (int i = 0; i < NUMTHRDS; i++)
arg[i].thread_id = i;
arg[i].sum = sum;
pthread_create(&callThd[i], &attr, count_pi, (void *)&arg[i]);
pthread_attr_destroy(&attr);
void *status;
for (int i = 0; i < NUMTHRDS; i++)
pthread_join(callThd[i], &status);
printf("Final Sum = %f \n", *sum);
free(sum);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
【问题讨论】:
【参考方案1】:主程序将自身发送给工作人员。
// simple.js
// Ask the new worker to load up the Emscripten-compiled page. This is a heavy operation.
worker.postMessage(
'cmd': 'load',
// If the application main .js file was loaded from a Blob, then it is not possible
// to access the URL of the current script that could be passed to a Web Worker so that
// it could load up the same file. In that case, developer must either deliver the Blob
// object in Module['mainScriptUrlOrBlob'], or a URL to it, so that pthread Workers can
// independently load up the same main application file.
'urlOrBlob': Module['mainScriptUrlOrBlob'] || _scriptDir,
'wasmMemory': wasmMemory,
'wasmModule': wasmModule,
'DYNAMIC_BASE': DYNAMIC_BASE,
'DYNAMICTOP_PTR': DYNAMICTOP_PTR
);
然后工人将其导入。
// simple.worker.js
if (typeof e.data.urlOrBlob === 'string')
importScripts(e.data.urlOrBlob);
else
var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
importScripts(objectUrl);
URL.revokeObjectURL(objectUrl);
因此Module
不是共享的,而是独立初始化的。
【讨论】:
这太奇怪了。为什么 emscripten 将主.js
设置为条目;然后用它来设置工人并再次将自己导入工人?我的意思是,我们不能不这样做就将逻辑分开吗?
你知道为什么吗?
我不确定,但分离他们的 ifdef 条件压缩逻辑可能是一项艰巨的工作。 github.com/emscripten-core/emscripten/blob/1.40.1/src/…
我明白了。我认为这会使代码难以阅读。无论如何,非常感谢。以上是关于Emscripten 中的“Module”变量机制,同时将 Pthread 编译为 worker的主要内容,如果未能解决你的问题,请参考以下文章
Emscripten WebAssembly:导出类“Import #13 module="GOT.func" 错误:模块不是对象或函数”
如何使用 emscripten 生成独立的 WebAssembly