У меня проблема синхронизации SharedArrayBuffer
с основным потоком.
Вот сценарий:
У меня есть два работника, которые обрабатывают различные аспекты моей программы. Первый работник отвечает за взаимодействие объектов, второй - за расчет видимости и т.д., А основной поток будет делать визуализацию.
Сначала первый Рабочий создает SharedArrayBuffer
со следующим расположением:
new SharedArrayBuffer(112);
[
Lock: 4 Byte
MetaInfo: 4 Byte
Location: 12 Byte
Scale: 12 Byte
Rotation: 16 Byte
Matrix: 64 Byte
]
Затем он отправляет SAB в основной поток и второй рабочий и сохраняет параметры шкалы местоположения и вращения в буфере. Каждый раз, когда он обновляет поля, он блокирует SAB, обновляет значения и устанавливает первый бит полей MetaInfo (флаг трансформирования) в true.
Второй рабочий будет вычислять матрицу из заданной шкалы местоположения и полей вращения, если флаг трансформирования установлен и сохраняет его в полях Матрица. После этого второй бит полей MetaInfo (флаг матрицы) будет установлен в true.
Основной поток теперь должен прочитать финальную матрицу, если установлен флаг матрицы.
Здесь возникает проблема: на рабочих можно заблокировать буфер, используя метод Atomics.wait
в полях Lock. Но основной поток не хватает таких функций, приводящих к заиканию и "прыжке". Существует ли последовательный способ запретить другому работнику писать в SAB во время процесса чтения?
Вот код моей оболочки SharedArrayBuffer
:
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);
}
}
Обратите внимание, что блокировка и бесплатный метод не используются в основном потоке, поскольку:
Примечание. Эта операция работает только с общим Int32Array и не разрешена в основном потоке.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait
Возможно ли, что эта установка может иметь несколько независимых полей в одном SharedArrayBuffer
или я должен использовать несколько SharedArrayBuffer
для каждого приложения.
После ряда исследований Atomics.wait()
что выбор предотвращения использования основного потока Atomics.wait()
заключается в том, чтобы избежать синхронной блокировки потоков, поскольку основной поток связан с событиями пользователя и рендерингом страницы, а также с другими службами и позволяет Atomics.wait()
приведет к плохому пользовательскому опыту в веб-приложении.
SharedArrayBuffer
API отрабатывался по OffscreenCanvas
API, который в настоящее время по- прежнему Unimplemented на Chrome, но доступен на Firefox.
Используя Atomics.wait()
холст, вы можете использовать Atomics.wait()
из веб-работника, предназначенного для рендеринга, применить свои операции gl
после чтения данных из буфера разделяемого массива, а затем вызвать gl.commit()
, который отобразит gl
к основной теме.
К сожалению, поскольку Firefox является единственным браузером, поддерживающим в настоящий момент API OffscreenCanvas
, а NW.js предназначен только для Chromium, эта особая задача синхронизации не представляется возможной для преодоления из-за отсутствия поддержки как Atomics.wait()
и WebGL в тот же поток на Chrome.
OffscreenCanvas
страдает от множества ошибок (например, холст исчезает после простоя в течение одной секунды) и, как вы упоминаете, доступен только в FF. Не повезло с этой функцией в данный момент :(
demo/
есть демонстрационные программы для справки, так как там не очень подробная документация.
SharedArrayBuffer
в четверг, где он неSharedArrayBuffer
.SharedArrayBuffer
через порты сообщений. Но, к сожалению, я работаю внутри nwjs в настоящее время в Chrome 60.