Блокировки и атомарность Блокировки - это механизм защиты для выполнения сложных, небезопасных операций с некоторыми данными, которые защищены блокировкой. Атомарные операции - это операции, которые никогда не могут наблюдаться только частично и не прерываются, если несколько потоков одновременно обращаются к одним и тем же переменным (обратите внимание, что в C ++ переменные, над которыми выполняются атомарные операции, называются атомарнымитоже).Блокировки - это абстрактная концепция, реализованная с использованием атомарных операций.
Как использовать мьютексы / блокировки A mutex - это стандартный способ выполнения блокировки: мьютекс всегда защищает некоторые переменныекоторые связаны с этим.Он либо заблокирован, либо разблокирован, и только один поток за раз может заблокировать его.Пока мьютекс заблокирован, поток может выполнять небезопасные операции над своими защищенными переменными, и гарантируется, что никакой другой поток не сможет вмешиваться или наблюдать частичные изменения, сделанные потоком, который удерживает блокировку.После того как поток завершил изменение переменных, он может разблокировать мьютекс, чтобы другие потоки теперь могли обращаться к защищенным переменным (блокируя сами мьютекс).
Обратите внимание, что всякий раз, когда поток хочет получить доступ к любому изЗащищенные переменные в любом случае, он должен заблокировать связанный мьютекс.В противном случае больше не гарантируется, что потоки не будут мешать работе друг друга.
Как реализованы блокировки? Насколько я знаю, блокировки / мьютексы всегда реализуются с использованием атомарных операций.,Одной из таких операций является атомный обмен : он позволяет считывать значение из переменной и записывать в него новое значение атомарно, поэтому никакой другой поток не может вмешиваться в этот процессили наблюдать это на полпути сделано.Мьютекс может быть реализован с использованием атомарного bool (true = LOCKED, false = UNLOCKED), и его блокировка выполняется следующим образом:
while(mutex.locked.exchange(LOCKED) == LOCKED);
Это всегда устанавливает мьютекс на LOCKED и читает предыдущийЗначение, и если оно было разблокировано, заканчивается.В этом сценарии мы являемся единственным потоком, который устанавливает мьютекс с UNLOCKED на LOCKED.
Разблокировка очень проста: mutex.locked = UNLOCKED;
Это просто устанавливает мьютекс на UNLOCKED, и затем он может быть снова заблокирован другими потоками.
Примечание Для простоты я упустил упорядочение памяти , аспект атомарности, который касается порядка, в котором изменения, сделанные одним потоком, становятся видимыми для другогопотоки (как и в некоторых порядках памяти, изменения могут наблюдаться не в том порядке, в котором они были внесены, а несколько потоков могут даже видеть изменения в непоследовательных порядках).Упорядочить память очень сложно.
Заключение Как правило, если вы действительно не знаете, что делаете, вы всегда должны использовать мьютексы и блокировки, а не атомарность,Хотя мьютексы медленнее, они достаточно сложны, чтобы в них уже войти, и их гораздо проще использовать правильно.Они автоматически работают с видимостью внесенных изменений, поэтому ваша программа становится проще для понимания и написания.