Подтвердить что ты не робот

Что более эффективно, базовая блокировка мьютекса или атомное целое?

Для чего-то простого, как счетчик, если несколько потоков будут увеличивать число. Я читал, что блокировки мьютексов могут снижать эффективность, поскольку потоки должны ждать. Итак, для меня самый эффективный атомный счетчик, но я читал, что внутренне это в основном блокировка? Поэтому, я думаю, я смущен, как можно быть более эффективным, чем другой.

4b9b3361

Ответ 1

Если у вас есть счетчик, для которого поддерживаются атомные операции, он будет более эффективен, чем мьютекс.

Технически атом будет блокировать шину памяти на большинстве платформ. Однако есть две улучшающие детали:

  • Невозможно приостановить поток во время блокировки шины памяти, но можно приостановить поток во время блокировки мьютекса. Это то, что позволяет получить гарантию без блокировки (которая ничего не говорит о блокировке - это просто гарантирует, что по крайней мере один поток достигнет прогресса).
  • Мьютексы в конечном итоге реализуются с атомикой. Так как вам нужна хотя бы одна атомная операция для блокировки мьютекса и одной атомной операции для разблокировки мьютекса, требуется, по крайней мере, два раза сделать блокировку мьютекса даже в лучших случаях.

Ответ 2

Поддержка процессоров Atomic-операций (сравнение и своп-команды) и вообще не использует блокировки, тогда как блокировки более зависимы от ОС и работают по-разному, например Win и Linux.

Замки фактически приостанавливают выполнение потоков, освобождая ресурсы процессора для других задач, но при очевидном перераспределении контекстных переключений при остановке/перезапуске потока. Напротив, потоки, пытающиеся выполнять атомарные операции, не ждут и продолжают попытки до достижения успеха (так называемое ожидание), поэтому они не несут накладных расходов контекста, но не освобождают ресурсы процессора.

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

Ответ 3

Атомные классы переменных в Java могут использовать команды сравнения и свопинга, предоставляемые процессором.

Здесь приводится подробное описание различий: http://www.ibm.com/developerworks/library/j-jtp11234/

Ответ 4

Минимальная (стандартизованная) реализация мьютекса требует 2 основных ингредиентов:

  • Способ атомарного переноса изменения состояния между потоками ( "заблокированное" состояние)
  • для обеспечения безопасности операций памяти, защищенных мьютексом, чтобы оставаться внутри защищенной области.

Нет никакого способа сделать его более простым, чем это из-за "синхронизации с", которое требует стандарт С++.

Минимальная (правильная) реализация может выглядеть так:

class mutex {
    std::atomic<bool> flag{false};

public:
    void lock()
    {
        while (flag.exchange(true, std::memory_order_relaxed));
        std::atomic_thread_fence(std::memory_order_acquire);
    }

    void unlock()
    {
        std::atomic_thread_fence(std::memory_order_release);
        flag.store(false, std::memory_order_relaxed);
    }
};

Из-за своей простоты (он не может приостановить поток выполнения), вполне вероятно, что при низкой конкуренции эта реализация превосходит std::mutex. Но даже тогда легко видеть, что для каждого целочисленного приращения, защищенного этим мьютексом, требуются следующие операции:

  • a atomic хранилище для выпуска мьютекса
  • a atomic compare-and-swap (read-modify-write) для получения мьютекса (возможно, несколько раз)
  • целочисленное приращение

Если вы сравниваете это с автономным std::atomic<int>, который увеличивается с помощью одного (безусловного) read-modify-write (например, fetch_add), разумно ожидать, что атомная операция (с использованием той же модели упорядочения) будет превосходить случай использования мьютекса.

Ответ 5

атомное целое - это пользовательский режим, там он намного эффективнее, чем мьютекс, который работает в режиме ядра. Объем атомного целого - это одно приложение, а объем мьютекса - для всего программного обеспечения на компьютере.

Ответ 6

Mutex - семантика уровня ядра, которая обеспечивает взаимное исключение даже при Process level. Обратите внимание, что это может быть полезно для расширения взаимного исключения по границам процесса, а не только внутри процесса (для потоков). Это дороже.

Атомный счетчик AtomicInteger, например, основан на CAS и обычно пытается попытаться выполнить операцию до достижения успеха. В принципе, в этом случае потоки расходятся или конкурируют за увеличение\уменьшают значение атомарно. Здесь вы можете видеть, что хорошие циклы процессора используются потоком, пытающимся работать с текущим значением.

Поскольку вы хотите поддерживать счетчик, AtomicInteger\AtomicLong будет лучшим для вашего использования.

Ответ 7

Большинство процессоров поддерживают атомарное чтение или запись, а часто и атомный cmp & swap. Это означает, что сам процессор записывает или считывает последнее значение за одну операцию, и может быть потеряно несколько циклов по сравнению с обычным целым доступом, тем более что компилятор не может оптимизировать вокруг атомных операций почти так же хорошо, как обычно.

С другой стороны, мьютекс представляет собой ряд строк кода для ввода и выхода, и во время этого выполнения другие процессоры, которые имеют доступ к одному и тому же местоположению, полностью застопорены, так что на них большие накладные расходы. В неоптимизированном высокоуровневом коде мьютексы вводят/выходят, а атомы будут функциональными вызовами, но для мьютекса любой конкурирующий процессор будет заблокирован, пока функция ввода мьютекса вернется, и пока ваша функция выхода будет запущена. Для атомарных, это только продолжительность фактической операции, которая заблокирована. Оптимизация должна снизить эту стоимость, но не все.

Если вы пытаетесь увеличить, то ваш современный процессор, вероятно, поддерживает атомный приращение/декремент, который будет большим.

Если это не так, то оно либо реализуется с использованием процессора cmp & swap, либо с использованием мьютекса.

мьютекса:

get the lock
read
increment
write
release the lock

Атомный cmp и обмен:

atomic read the value
calc the increment
do{
   atomic cmpswap value, increment
   recalc the increment
}while the cmp&swap did not see the expected value

Итак, у этой второй версии есть цикл [если другой процессор увеличивает значение между нашими атомными операциями, поэтому значение больше не соответствует, а приращение будет неправильным), что может затянуться [если есть много конкурентов], но в целом все равно быстрее, чем версия мьютекса, но версия мьютекса может позволить этому процессору переключиться на задачу.