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

Вид: 46741|Ответ: 7

[Источник] Волатильность против блокировки против блокировки

[Скопировать ссылку]
Опубликовано 27.08.2018 14:40:35 | | |
Допустим, есть класс, содержащий публичное поле счётчика int, доступное несколькими потоками, и это число будет только увеличиваться или уменьшаться.

При добавлении этого поля какую из следующих схем следует использовать и почему?

  • lock(this.locker) this.counter++;
  • Interlocked.Increment (см. this.counter);
  • Измените модификатор доступа от counter на публичный волатильный


Хуже всего (ни один из них не работает)

Измените модификатор доступа от counter на публичный волатильный

Этот подход на самом деле совсем не безопасен, и суть волатильности в том, что несколько потоков, работающих на нескольких процессорах, буферизируют данные и перестраивают выполненные инструкции.

Если он неволатильный, то при увеличении числа CPU B нужно подождать некоторое время, чтобы увидеть это значение, что может привести к проблемам.

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

Добавление значения переменной фактически требует трёх шагов

1. Чтение, 2. Добавить 3. Писать

Предположим, что поток A читает значение счётчика как 1 и не готов к увеличению, затем поток B также считывает значение счетчика как 1, и тогда оба потока начинают выполнять инкрементальные и записывающие операции. Значение финального счётчика — 2. Это неправильно, оба потока выполнили операцию увеличения, и правильный результат должен быть 3. Поэтому называть его нестабильным — это просто небезопасно.

Так лучше

lock(this.locker) this.counter++;

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

Лучшие

Interlocked.Increment (см. this.counter);

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

Но я не совсем уверен, сможет ли это также решить проблему порядка инструкций процессора, или его нужно использовать вместе с волатильностью и этим инкрементом.

Дополнение: Какие проблемы волатил решает хорошо?

Поскольку волатильный не может предотвратить многопоточность, что он может сделать? Хороший пример — у вас есть два потока: один всегда записывает в переменную, допустим, эта переменная — queneLength, а другой всегда читает данные из этой переменной. Если queueLenght не волатильна, поток A может читать 5 раз, но поток B может видеть задержанные данные или даже данные в неправильном порядке. Один из вариантов — использовать блокировку, но в данном случае можно использовать и волатильный. Это гарантирует, что поток B всегда видит последние данные, записанные потоком A, но эта логика работает только если вы не читаете их при записи и не записываете их во время чтения. Когда несколько потоков хотят выполнять операции чтения-модификации-записи, нужно использовать Interlocked или Lock.





Предыдущий:Метод шифрования Java MD5
Следующий:Linq реализует не в и в условных запросах SQL
Опубликовано 29.08.2018 16:21:42 |
Здравствуйте, код, который вы делали ранее, который объединяет гистограммы с высокими диаграммами и гистограммы с сверлением? Хотел бы спросить, можно ли отправить код, который можно редактировать на интерфейсе https://jshare.com.cn/demos/hhhhDz?hc-theme=grid-light?
Опубликовано 29.08.2018 16:22:13 |
Вся сеть — это просто ваш ресурс.
Опубликовано 29.08.2018 16:22:55 |
Потому что предыдущие 90 лет назад невозможно было оставить сообщение. Так что
Опубликовано 29.08.2018 16:40:40 |
Удобно ли добавить контактную информацию? Проконсультируйтесь с вами
 Хозяин| Опубликовано 15.09.2018 13:10:16 |
приватный статический int safeInstanceCount = 0; Работайте с атомами
System.Threading.Interlocked.Increment(ссылка safeInstanceCount); Самоувеличение 1
System.Threading.Interlocked.Decrement(ссылка safeInstanceCount); Самоминус 1
Опубликовано 21.05.2020 16:43:54 |
Поддержите владельца в том, чтобы он делился
 Хозяин| Опубликовано 11.06.2020 15:00:16 |
1. Концепция

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

2. Класс

Статический класс System.Threading.Interlocked

3. Часто используемые функции (см. остальное)

1. публичный статический int Decrement (ссылка int location); Декрин значения указанной переменной в виде атомарной операции и сохраняет результат

Эквивалентно lock(obj){i--; }

2. публичный статический int Increment(ссылка на int location); Увеличите значение указанной переменной в виде атомарной операции и храните результат

Эквивалент lock(obj){i++; }
Отказ:
Всё программное обеспечение, программные материалы или статьи, публикуемые Code Farmer Network, предназначены исключительно для учебных и исследовательских целей; Вышеуказанный контент не должен использоваться в коммерческих или незаконных целях, иначе пользователи несут все последствия. Информация на этом сайте взята из Интернета, и споры по авторским правам не имеют отношения к этому сайту. Вы должны полностью удалить вышеуказанный контент с компьютера в течение 24 часов после загрузки. Если вам нравится программа, пожалуйста, поддержите подлинное программное обеспечение, купите регистрацию и получите лучшие подлинные услуги. Если есть нарушение, пожалуйста, свяжитесь с нами по электронной почте.

Mail To:help@itsvse.com