всегда можно заблокировать блокировку в течение всего кода, который обращается к любым общим данным, но это медленно, поскольку это означает, что только один поток за раз может выполнять значительные куски кода.
В зависимости от данных, однако, могут быть ярлыки, которые безопасны и быстро. Если это простое целое число (а по целому я имею в виду собственный размер слова процессора, т. Е. Не 64-разрядный бит на 32-битном процессоре), вам может не понадобиться блокировать: если один поток пытается записать на целое число, а другое читает его в одно и то же время, читатель либо получит старое значение, либо новое значение, никогда не смешивая их. Если читателю все равно, что он получил старое значение, тогда нет необходимости в блокировке.
Если, однако, вы обновляете два целых числа вместе, и для читателя было бы плохо получить новое значение для одного и старого значения для другого, тогда вам понадобится блокировка. Другим примером является то, что поток увеличивает число. Обычно это включает чтение, добавление и запись. Если вы читаете старое значение, то другому удается читать, добавлять и записывать новое значение, тогда первый поток добавляет и записывает новое значение, оба полагают, что они увеличили эту переменную, но вместо того, чтобы увеличивать его дважды, это было только один раз увеличивается. Для этого требуется либо блокировка, либо использование примитива атомного инкремента, чтобы гарантировать, что цикл чтения/изменения/записи не может быть прерван. Есть также атомарные тестовые и заданные примитивы, поэтому вы можете прочитать значение, выполнить некоторую математику, затем попробуйте, чтобы записать его обратно, но запись только удалась, если она все еще содержит исходное значение. То есть, если другой поток изменил его с момента его прочтения, тестовый набор будет терпеть неудачу, тогда вы можете отбросить свое новое значение и начать с чтения значения, заданного другим потоком, и попытаться выполнить тестирование и -изложите его снова.
Указатели действительно являются целыми числами, поэтому, если вы настроили структуру данных, тогда сохраните указатель на нее, где другой поток может найти ее, вам не нужно блокировать, пока вы полностью настроили структуру до вы сохраняете его адрес в указателе. Другой поток, читающий указатель (он должен обязательно прочитать указатель только один раз, то есть путем его хранения в локальной переменной, а затем использовать только это, чтобы ссылаться на структуру с того времени) либо увидит новую структуру, либо старую один, но не промежуточное состояние. Если большинство потоков считывает структуру только через указатель, и все, кто хочет писать, делают это либо с помощью блокировки, либо с помощью атомного теста и набора указателя, этого достаточно. Каждый раз, когда вы хотите изменить какой-либо элемент структуры, вы должны скопировать его на новый, изменить новый, а затем обновить указатель. Это, по сути, работает механизм ядра RCU (чтение, копирование, обновление).