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

С# многопоточность: требуется захват чтения?

Нужно ли приобретать блокировку переменной перед ее чтением из нескольких потоков?

4b9b3361

Ответ 1

Короткий ответ: это зависит.

Долгий ответ:

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

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

  • Если это "примитивный" тип не более 32 бит (например, byte, short, int), вы можете получить устаревшие (старые) данные при чтении. Если это вас не беспокоит, вы настроены. Если устаревшие данные нежелательны, изменение переменной volatile может устранить эту проблему без дополнительной синхронизации для чтения. Но если у вас есть гоночные авторы, вам нужно будет следовать тем же советам, что и для long ниже.

  • Если это "примитивный" тип длиной более 32 бит (например, long, decimal, double), вам нужна синхронизация, иначе вы могли бы прочитать "половину" одного значения, "половина" другого, и получить сумасшедшие результаты. Для этого рекомендуется использовать методы в классе Interlocked для чтения и записи.

  • Если это ссылочный тип, вам понадобится синхронизация, чтобы избежать недопустимого состояния (пример изображения Jeff Lamb является хорошим). Для этого может быть достаточно lock. Опять же, вам нужно заблокировать как чтение, так и запись.

Есть еще несколько моментов, которые следует учитывать (как долго блокировать, например), но я думаю, этого достаточно, чтобы ответить на ваш вопрос.

Ответ 2

Это зависит от типа переменной и вашей платформы. Например, чтение Int64s не гарантируется атомарным на 32-битных машинах. Следовательно, Interlocked.Read.

Ответ 3

Если загрузка значения выполняется в 1 команде сборки, нет необходимости получать блокировку. Вам все равно, изменилось ли значение 10 минут назад или 1 микросекунда назад. Вы просто хотите значение сейчас.

Однако, если вы загружаете массив HUGE или изображение или что-то в этом роде, вероятно, было бы неплохо его заблокировать. Теоретически вы можете получить выгрузку при загрузке данных и иметь половину первого элемента и половину второго элемента.

Если это простая переменная, хотя, например, bool или int, она не нужна.

Ответ 4

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

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

Такая блокировка была бы полезна, если вы делаете много чтения и не много записей.

Как и в случае с большинством проблем с многопоточным анализом, достаточно исследовать его, чтобы понять, действительно ли это соответствует вашей проблеме, ReadWriterLock не подходит для каждой ситуации блокировки.

Ответ 5

Чтение не требует блокировки; пока вы не заботитесь о "правильности" чтения. Это опасно, если вы пытаетесь писать без блокировки.

Ответ 6

Это зависит от того, является ли это локальной или общей переменной, и может ли что-то еще писать ей в это время и что вы собираетесь делать после прочтения.

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

Ответ 7

Если это константа, no.

Если это обновляемое значение, да, если вам нужна согласованность.

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

Ответ 8

Ответ, это зависит. Если значение переменной не изменяется, когда потоки обращаются к переменной. в противном случае это необходимо.

Кроме того, вы можете использовать Interlocked.XXX для поддержания атомарности при чтении\записи переменной.

Ответ 9

нужно? Нет.

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

Ответ 10

Это 100% необходимо, если вы на 100% не уверены, что значение переменной не изменится, когда потоки чтения запущены.

Ответ 11

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

Ответ 12

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