Javascript Синхронизировать SharedArrayBuffer с основным потоком

1

У меня проблема синхронизации 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 для каждого приложения.

  • 0
    Вы только начали этот проект совсем недавно? Я вижу, что Chrome только что развернул поддержку SharedArrayBuffer в четверг, где он не SharedArrayBuffer .
  • 0
    Это хорошая новость, возможно, она решает проблему отправки SharedArrayBuffer через порты сообщений. Но, к сожалению, я работаю внутри nwjs в настоящее время в Chrome 60.
Показать ещё 4 комментария
Теги:
multithreading
web-worker

1 ответ

1

После ряда исследований 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.

  • 0
    Да, я читал об этом, а также сделал несколько тестов. Но OffscreenCanvas страдает от множества ошибок (например, холст исчезает после простоя в течение одной секунды) и, как вы упоминаете, доступен только в FF. Не повезло с этой функцией в данный момент :(
  • 0
    Есть еще одна возможность, которую вы можете проверить. Есть библиотека синхронизации, называемая parlib, которая облегчает атомарные операции, используя polyfill. В каталоге demo/ есть демонстрационные программы для справки, так как там не очень подробная документация.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню