1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9

# конспект · шаг 9 из 9

Конспект: взаимное исключение и модели памяти

выжимка - её можно унести в заметки

Понятия

Чередование - общий порядок операций всех потоков, где операции каждого идут в порядке его программы; у двух потоков по a и b операций их C(a + b, a). Гонка - результат зависит от чередования.

Критическая секция - код, где одновременно не больше одного потока. Требования к замку: взаимоисключение (безопасность), отсутствие взаимоблокировки и отсутствие голодания (живость).

Состояние протокола в SC - строки всех потоков плюс общая память; в TSO добавляются буферы записи. Полный перебор конечной модели доказывает проверяемое свойство в этой модели. У пекарни с неограниченными талонами состояний бесконечно много.

Последовательная согласованность - исполнение равно какому-то чередованию. TSO (x86) - записи идут через буфер ядра, чтение может обогнать свою запись в другую ячейку. Барьер - ждать, пока буфер не опустеет.

Что унести

c = c + 1 - ТРИ ОПЕРАЦИИ
1 инкремент на поток: 20 чередований, правильный итог - в 2
2 инкремента: 924 чередования, итоги 2, 3, 4; четвёрка - в 6
итог опускается до 2 при любом числе инкрементов
редкие переключения: тест иногда зелёный, иногда -117 из 400
ЗАМКИ НА ДВА ПОТОКА              состояний  итог
наивный: проверил, поднял флаг   16         двое в секции
LockOne: поднял флаг, ждёт       12         оба ждут вечно
LockTwo: только жертва           -          один ждёт вечно
Петерсон:                        26         всё соблюдено
  f[i] = 1; v = i
  ждать, пока f[j] == 1 и v == i
  секция; f[i] = 0
переставить первые две строки - двое в секции за 6 шагов
ЗАМКИ НА n ПОТОКОВ
фильтр: n − 1 уровней; level[i] = L, потом victim[L] = i,
        ждать, пока кто-то на уровне >= L и жертва - я
        уровень L проходят не больше n − L; 3 потока - 894 сост.
пекарня (Лэмпорт, 1974): флаг; талон = max + 1;
        ждать всех с флагом и меньшей парой (талон, номер)
        «кто первый пришёл»: не больше n − 1 обгонов
        талоны растут без предела, ничьи бывают
нижняя граница (Бёрнс, Линч): на чтениях и записях - n ячеек
МОДЕЛИ ПАМЯТИ
тест: x = 1; r0 = y  ||  y = 1; r1 = x
согласованная: [0,1] [1,0] [1,1]     TSO: ещё и [0,0]
TSO + барьер после записи: снова без [0,0]
Петерсон: согласованная - 26 состояний, чисто
          TSO - 400, двое в секции; барьер после v = i - 134, чисто
ARM, POWER: переставляют и записи между собой
язык: нет гонок данных → последовательная согласованность
      (Java, C++, Go); atomic по умолчанию - seq_cst
ПОИСК СЦЕНАРИЯ ПОЛОМКИ
в ширину (очередь): первое плохое состояние - ближайшее
в глубину (стек): те же состояния, путь произвольный

Ловушки джокера

«У меня работает». Гонку не ловят тестами: плохие чередования редки, на машине разработчика их почти нет.

«Если не занято - займи». Проверка и запись с зазором между ними пропускают двоих.

Порядок двух строк. Уступка раньше флага ломает Петерсона, жертва раньше уровня ломает фильтр.

Ничья талонов. Без сравнения номеров потоков двое с одинаковым талоном входят вместе.

Переполнение талона. Обнулившийся талон обгоняет всю очередь.

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

Барьер не там. Нужен между последней записью протокола и первым чтением чужих данных, а не после каждой строки.

  • Монитор: общее состояние и замок; Condition.wait атомарно отпускает замок и перед возвратом захватывает его. Предикат проверяется в while. Notify не копит разрешения, семафор копит.

  • RW-lock: читатели совместимы, писатель исключителен. Предпочтение читателей может голодать запись, предпочтение писателей - чтение. FIFO объединяет соседние чтения, но требует корректной отмены билетов.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.