Ця стаття є дзеркальною статтею машинного перекладу, будь ласка, натисніть тут, щоб перейти до оригінальної статті.

Вид: 46741|Відповідь: 7

[Джерело] Волатильна проти взаємоблокуваної проти блокування

[Копіювати посилання]
Опубліковано 27.08.2018 14:40:35 | | |
Припустимо, існує клас, який містить публічне поле лічильника інтелекту, доступне кількома потоками, і це число лише зростає або зменшується.

При додаванні цього поля, яку з наступних схем слід використовувати і чому?

  • lock(this.locker) this.counter++;
  • Interlocked.Increment (посилається на this.counter);
  • Змінити модифікатор доступу counter на публічний волатильний


Найгірше (жоден із них насправді не працює)

Змінити модифікатор доступу counter на публічний волатильний

Цей підхід насправді зовсім не є безпечним, і суть волатильності в тому, що кілька потоків, що працюють на кількох процесорах, буферизують дані та переставляють виконані інструкції.

Якщо він енергонезалежний, то коли CPU A збільшується на значення, CPU B має почекати деякий час, щоб побачити зростання, що може призвести до проблем.

Якщо він волатильний, це гарантує, що обидва процесори бачать однакове значення одночасно. Але це не уникає перехресних операцій читання та запису.

Додавання цінності змінній фактично займає три етапи

1. Читання, 2. Додати 3. Писати

Припустимо, що потік A читає значення лічильника як 1 і не готовий до збільшення, тоді потік B також зчитує значення лічильника як 1, і обидва потоки починають виконувати операції інкрементального та запису. Значення фінального лічильника — 2. Це неправильно, обидва потоки виконали операцію збільшення, і правильний результат має бути 3. Тож маркувати його як мінливий — це просто небезпечно.

Так краще

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

Так це безпечно (звісно, не забувайте блокувати всюди, де хочете отримати доступ до цього прилавка). Це запобігає виконанню будь-якого іншого потоку заблокованого коду. І це також запобігає згаданій вище проблемі послідовності інструкцій у багатьох процесорах. Проблема в тому, що блокування працює повільно, і якщо ви використовуєте блокування в інших, не пов'язаних з цим місцях, це може заблокувати інші потоки.

Найкраще

Interlocked.Increment (посилається на this.counter);

Це безпечно і дуже ефективно. Він виконує три операції читання, збільшення та запис в одному атомі без переривання посередині. Оскільки це не впливає на інший код, вам не потрібно запам'ятовувати блокування в інших місцях. І він також дуже швидкий (як каже MSDN, на сучасних процесорах це часто просто інструкція).

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

Додаток: Які проблеми волатильний продукт вирішує добре?

Оскільки волатильний не може запобігти багатопотоковості, що він може робити? Гарний приклад — у вас є два потоки: один завжди записує у змінну, припустимо, ця змінна queneLength, а інший завжди читає дані з цієї змінної. Якщо queueLongght не є волатильним, потік A може зчитувати 5 разів, але потік B може бачити затримані дані або навіть дані у неправильному порядку. Один із варіантів — використовувати блокування, але в цьому випадку можна також використовувати волатильний. Це гарантує, що потік B завжди бачить останні дані, написані потоком A, але ця логіка працює лише якщо ви не читаєте їх під час написання і не записуєте під час читання. Якщо кілька потоків хочуть виконувати операції читання-модифікації-запису, потрібно використовувати Interlocked або Locked.





Попередній:Метод шифрування 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(ref safeInstanceCount); Самозростання 1
System.Threading.Interlocked.Decrement(ref safeInstanceCount); Self-minus 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