I have a problem synchronizing a SharedArrayBuffer to the main thread.
Here is the scenario:
I got two worker which handle different aspects of my program. The first worker is responsible for object interaction, the second for calculating visibilities etc and the main thread will do the visualization.
At first the first Worker creates a SharedArrayBuffer with the following layout:
new SharedArrayBuffer(112);
[
Lock: 4 Byte
MetaInfo: 4 Byte
Location: 12 Byte
Scale: 12 Byte
Rotation: 16 Byte
Matrix: 64 Byte
]
He then sends the SAB to the main thread and second Worker and stores the location scale and rotation attributes in the Buffer. Every time he updates the fields he locks the SAB, updates the values and sets the first bit of the MetaInfo fields (transform flag) to true.
The second Worker will compute the matrix from the given location scale and rotation fields if the transform flag is set and save it in the Matrix fields. Afterward the second bit of the MetaInfo fields (matrix flag) will be set to true.
The main thread now needs to read the final matrix if the matrix flag is set.
Here comes the problem: On the workers it is possible to lock the buffer using the Atomics.wait method on the Lock fields. But the main thread lacks such features resulting in stuttering and "hopping". Is there a consistent way to prevent the other worker from writing into the SAB during the reading process?
Here is the code of my SharedArrayBuffer wrapper:
class SharedObject {
SharedBuffer: SharedArrayBuffer; // the shared array buffer
Lock: Int32Array; // view for lockíng the buffer
MetaInfo: Int32Array; // view for meta info
Location: Float32Array;
constructor(buffer) {
// if valid buffer is passed assign it to this object
if (buffer !== undefined && buffer instanceof SharedArrayBuffer && buffer.byteLength == 112) {
this.SharedBuffer = buffer;
} else {
// create new shared array buffer
this.SharedBuffer = new SharedArrayBuffer(112);
}
this.Lock = new Int32Array(this.SharedBuffer, 0, 4);
this.MetaInfo = new Int32Array(this.SharedBuffer, 4, 8);
[ ... init the rest of the views ... ]
// init the lock element
if (buffer === undefined) {
Atomics.store(this.Lock, 0, 1);
}
}
lock() {
Atomics.wait(this.Lock, 0, 0);
Atomics.store(this.Lock, 0, 0);
return true;
}
free() {
if (Atomics.wake(this.Lock, 0, 1) == 0) {
Atomics.store(this.Lock, 0, 1);
}
return true;
}
setFlag(flag) {
this.MetaInfo[0] = this.MetaInfo[0] | flag;
}
isFlagSet(flag) {
return (this.MetaInfo[0] & flag) > 0;
}
resetFlag(flag) {
this.MetaInfo[0] = this.MetaInfo[0] - (this.MetaInfo[0] & flag);
}
}
Note the lock and free method are not use able in main thread since:
Note: This operation only works with a shared Int32Array and is not allowed on the main thread.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait
Is this setup even possible to have multiple independent fields in one SharedArrayBuffer or should I consider using multiple SharedArrayBuffer for each application.
SharedArrayBufferon Thursday where it's not behind a flag.SharedArrayBuffervia message ports. But sadly i am working inside nwjs currently in chrome 60.SharedArrayBuffer. Are you required to use nwjs or will you be able to switch easily to using browser-based JavaScript?var sab = new SharedArrayBuffer(4); var lock = new Int32Array(sab); Atomics.wait(lock, 0, 0);results in:VM1347:3 Uncaught TypeError: Atomics.wait cannot be called in this context