Как вы решаете проблему ABA при использовании mwaitx?

Инструкция AMD mwaitx позволяет дождаться изменения адреса и имеет ограниченную продолжительность. Невозможно определить, проснулся ли он из-за изменения значения или из-за прерывания.

Вы всегда можете проверить адрес, чтобы увидеть, не изменился ли он, но это приводит к проблеме ABA, когда он мог измениться, а затем измениться обратно.

Это может привести к проблеме, когда вы можете захотеть отправить запрос на обновление для блока данных, если был получен доступ к связанной с ним блокировке, но если блокировка получена, использована, а затем освобождена, структура данных изменилась, но значение блокировки не изменилось. t КАЖЕТСЯ изменился, и поток, использующий mwaitx, не знает о доступе к блокировке.

Есть ли обходной путь для этого или я застрял?

Не уверен, каков ваш вариант использования, но обычно либо 1) он не меняется обратно, потому что это будет делать ваш код, либо 2) если кто-то еще изменил его, тогда все в порядке, вернитесь к ожиданию

Jester 11.01.2023 02:03

@harold я добавил контекст

Badasahog 11.01.2023 02:14

Стандартное решение проблемы ABA — прикрепить к значению счетчик изменений. Таким образом, если значение изменится обратно, счетчик изменений все равно будет другим.

Raymond Chen 11.01.2023 02:20

@RaymondChen, что противоречит цели использования mwaitx, не так ли?

Badasahog 11.01.2023 02:44

Нет. Если вы хотите использовать его для мониторинга блокировки, вы можете выбрать среднее значение младшего бита по сравнению со свободным, а старшие биты будут счетчиком, который делает его уникальным. Взять блокировку будет lock bts dword [mem], 0 для проверки и установки младшего бита. Снятие блокировки будет add dword [mem], 1 (без префикса lock, так как никакие другие потоки не будут изменять значение; в лучшем случае они установят младший бит, который уже был установлен. Или просто загрузите значение блокировки, включите его и выполните обычный mov выпуск-хранилище, но память-назначение add эквивалентна.)

Peter Cordes 11.01.2023 05:41

@PeterCordes В моем примере кода я считаю, что совершил ошибку: я думаю, что вы должны monitor, прежде чем пытаться получить спин-блокировку, так как в противном случае возможно короткое окно, в котором другой поток мог снять блокировку до того, как вы установите монитор . Знаете ли вы рекомендуемую последовательность инструкций?

fuz 15.01.2023 03:22

@fuz: О, хорошая мысль. IDK, если вы можете xchg после monitor, не вызывая мгновенного пробуждения. Возможно, если вы не получите блокировку с первой попытки, monitor / load / test+jcc / mwait, чтобы у вас была окончательная проверка только для чтения после того, как монитор установлен, чтобы убедиться, что текущее значение соответствует тому, которое гарантирует спящий режим. Но это всего лишь предположение с моей стороны, я не перепроверял документы и не искал заведомо хороший пример, например, использует ли Linux mwait в futex, если на этом ядре нет другой задачи для запуска.

Peter Cordes 15.01.2023 04:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Идея состоит в том, чтобы использовать mwaitx в качестве оптимизации, а не в качестве единственного примитива синхронизации. Для этого варианта использования не имеет значения, может ли он время от времени выходить из строя.

Скажем, например, вы хотите установить спин-блокировку

        mutex   dd 0

установив его на 1, если раньше он удерживался 0. Простой способ сделать это - дождаться, пока блокировка станет нулевой, например. так:

again:  mov     ebx, 1
        xchg    [mutex], ebx  ; try to claim mutex
        test    ebx, ebx      ; did we succeed?
        jnz     again         ; if not, try again

Этот цикл, конечно, довольно неэффективен: если блокировка удерживается другим потоком, он очень быстро вращается, что приводит к большому количеству дорогостоящих обращений к шине RMW. Мы можем уменьшить нагрузку с помощью инструкции pause, но было бы еще лучше, если бы мы узнали, что блокировка удерживается, и попытались бы потребовать ее только после того, как узнали, что другой поток освободил блокировку.

Инструкции monitor / mwait предоставляют возможность сделать это: вы устанавливаете адрес для отслеживания, а затем вас замечают, когда происходит что-то интересное. Только тогда вы пытаетесь получить замок, спасая вас от вращения, если вы знаете, что не получите его. Не повредит, если mwait вернется раньше: вы просто не получите замок, а затем вернетесь к его ожиданию.

again:  mov     ebx, 1
        xchg    [mutex], ebx  ; try to claim mutex
        test    ebx, ebx      ; did we succeed?
        jz      gotit

        lea     rax, [mutex]  ; address to monitor
        xor     ecx, ecx      ; no extensions
        xor     edx, edx      ; no hints
        monitor               ; start to monitor the mutex

        cmp     [mutex], ebx  ; did the mutex change state meanwhile? (see note)
        jne     again         ; if yes, try to claim it again

        xor     ecx, ecx      ; no extensions
        xor     eax, eax      ; no hints
        mwait                 ; wait for mutex to change
        jmp     again         ; once it changed, try to get the lock again

gotit:  ...

Примечание: проверка на изменение статуса необходима после настройки монитора, чтобы поймать другой поток, освобождающий мьютекс после того, как мы попытаемся его заявить, но до того, как мы активируем монитор.

Хотя это хорошо и все такое, есть новая проблема: если другой поток какое-то время не уступает, сложные реализации мьютекса могут захотеть переключиться на другую реализацию, например. тот, где ядро ​​заботится о блокировке. Это позволяет ждать, пока блокировка станет доступной, без фактического запуска потока, освобождая ресурсы для других пользователей.

Этого трудно достичь с monitor и mwait: период ожидания неограничен и может быть очень долгим. Инструкции AMD mwaitx и monitorx очень похожи, но решают эту проблему: они позволяют вам установить тайм-аут, после которого mwaitx возвращается, даже если область памяти не изменилась. Таким образом, вы можете использовать такой алгоритм, как «попытаться запросить блокировку 10 раз, вращая и ожидая, а затем перейти к блокировке на основе ядра» и быть достаточно уверенным во времени, которое требуется для выполнения.

Чтобы избежать состояния гонки, когда другой поток разблокируется между вашим monitor и вашим mwait, Энди Глю предлагает monitor перед циклом, а затем внутри цикла проверить только для чтения и mwait. blog.andy.glew.ca/2010/11/httpsemipublic.html Так монитор уже поставлен на охрану до последней проверки только для чтения перед сном. Видимо не нужно повторно запускать monitor? Но в пользовательском пространстве вам, вероятно, следует перезапустить monitorx, так как поток может быть на другом ядре ЦП, когда вы просыпаетесь, если он был отменен по прерыванию таймера.

Peter Cordes 15.01.2023 09:08

@PeterCordes Я предполагаю, что переключение контекста в любом случае сделает мониторы недействительными. Статья показалась мне немного запутанной, поэтому я добавил код, который должен работать в любом случае.

fuz 16.01.2023 01:06

Другие вопросы по теме