проблема когерентности кэша между двумя ядрами на одном процессоре - PullRequest
0 голосов
/ 17 апреля 2020

Наличие двух процессов p1 и p2, каждый из которых работает на разных ядрах, скажем, c1 и c2 (оба ядра находятся на одном физическом процессоре). Оба этих ядра имеют различный кэш L1 и L2, совместно используя общий кэш L3. Оба p1 и p2 используют указатель ptr (ptr находится в разделяемой памяти). Процесс p1 инициализирует ptr & p2, как предполагается, просто использует его. Обращаясь к cra sh в p2, поскольку он видит ptr как 'NULL' изначально (хотя через некоторое время, возможно, из-за когерентности кэша, p2 увидит правильное значение ptr). У меня есть следующие вопросы, связанные с этим:

  1. Как может возникнуть описанная выше ситуация (p2 видит нулевое значение ptr), хотя какая-то форма протокола когерентности кэша была бы использована?
  2. В случае архитектуры с общей шиной / памятью разные процессоры (на разных сокетах) обычно следуют протоколам отслеживания шины для согласованности кэша. Я хочу знать, какие протоколы согласованности кэша используются в случае, когда два ядра (оба ядра на одном физическом процессоре) имеют свой собственный кэш l1 / l2 при совместном использовании общего кеша l3.
  3. Есть ли способ проверить, какой протокол кэширования используется (это для системы Ubuntu 16.04)?

1 Ответ

3 голосов
/ 17 апреля 2020

x86 согласован с кешем даже через несколько сокетов (как и все другие реальные ISA, которые вы можете запускать через std::thread). Модель упорядочения памяти x86 - это программный порядок + буфер хранения с пересылкой в ​​хранилище.

Формальная модель: Лучшая модель памяти x86: x86-TSO . Неофициально: http://preshing.com/20120930/weak-vs-strong-memory-models/

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


Почти наверняка p2 читает общую память перед p1 пишет это. Coherence не создает синхронизацию самостоятельно. Если p1 и p2 оба подключаются к общей памяти асинхронно, ничто не мешает p2 читать до записи p1.

Вам нужны какие-то данные флаг готовности, который проверяет p2 с помощью std::memory_order_acquire перед чтением указателя. Или просто вращайте при загрузке указателя, пока не увидите значение, отличное от NULL.

(Используйте mo_acquire при загрузке указателя atomi c, чтобы избежать переупорядочения во время компиляции или переупорядочения во время выполнения при не x86, с вещами, к которым вы обращаетесь позже, используя этот указатель. Или для использования указателя понадобится только mo_consume, но компиляторы усиливают его до mo_acquire. Это нормально для x86; приобретение в любом случае бесплатно.)

...