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

Критические разделы с многоядерными процессорами

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

Но что происходит, когда у вас действительно есть несколько физических процессоров? Кажется, что простой арифметики уровня инструкций недостаточно, b/c с двумя процессорами, потенциально выполняющими свои тестовые и заданные операции в одно и то же время, то, что вам действительно нужно для поддержания атомарности, является доступ к местоположению разделяемой памяти мьютекс. (И если местоположение разделяемой памяти загружено в кеш, есть и целая проблема с сохранением кеша, тоже...)

Похоже, что это повлечет за собой гораздо больше накладных расходов, чем одноядерный случай, так что вот здесь вопрос: насколько это хуже? Это хуже? Мы просто живем с этим? Или обойти его, применяя политику, что все потоки внутри группы процессов должны жить на одном физическом ядре?

4b9b3361

Ответ 1

Многоядерные/SMP-системы - это не только несколько процессоров, склеенных друг с другом. Там явная поддержка для параллелизма. Все примитивы синхронизации реализованы с помощью аппаратного обеспечения в соответствии с atomic CAS. Команда либо блокирует шину, разделяемую процессорами и контроллером памяти (и устройствами, которые выполняют DMA), и обновляет память, либо просто обновляет память, полагаясь на отслеживание кэша. Это, в свою очередь, вызывает алгоритм cache coherency, чтобы заставить всех вовлеченных сторон сбросить свои кеши.

Отказ от ответственности - это очень простой описание, здесь есть более интересные вещи, такие как виртуальные или физические кэши, политики обратной записи кэша, модели памяти, заборы и т.д. и т.д.

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

Ответ 2

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

На чипах Intel, например, у вас есть инструкция cmpxchg. Он сравнивает значение, хранящееся в ячейке памяти, с ожидаемым значением и обменивает его для нового значения, если они совпадают. Если вам предшествует инструкция "lock", она гарантированно будет атомарной по отношению ко всем ядрам.

Ответ 3

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

Ответ 4

Или обойти его, применяя политику, согласно которой все потоки внутри группы процессов должны жить на одном и том же физическом ядре?

Это отменит всю точку многопоточности. Когда вы используете блокировку, семафор или другие методы синхронизации, вы полагаетесь на ОС, чтобы убедиться, что эти операции взаимосвязаны, независимо от того, сколько ядер вы используете.

Время перехода на другой поток после освобождения блокировки в основном определяется стоимостью коммутатора контекста. В этом поток SO имеет дело с перераспределением ресурсов контекста, поэтому вы можете проверить это.

Есть и другие интересные темы:

Вы также должны прочитать эту статью MSDN: Понимание влияния методов с низким уровнем блокировки в многопоточных приложениях.

Ответ 5

Хорошо, в зависимости от того, какие типы компьютеров вы кладете вокруг дома, сделайте следующее: Напишите простое многопоточное приложение. Запустите это приложение на одном ядре (Pentium 4 или Core Solo), а затем запустите его на многоядерном процессоре (Core 2 Duo или аналогичном) и посмотрите, насколько велика скорость.

Согласитесь, это несправедливые сравнения, поскольку Pentium 4 и Core Solo намного медленнее независимо от ядер, чем Core 2 Duo. Возможно сравнить между Core 2 Duo и Core 2 Quad с приложением, которое может использовать 4 или более потоков.

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

Что касается вашего окончательного предложения о том, что все потоки на одном и том же физическом ядре полностью поражают точку многоядерного компьютера!

Ответ 6

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

Более элегантным решением является использование блока семафора HW, если процессор имеет такую ​​функцию. Семафор HW представляет собой простую очередь, которая может иметь размер no_of_cores -1. Так происходит в процессоре TI 6487/8. Вы можете запросить семафор напрямую (и цикл до его выпуска) или выполнить косвенный запрос, который приведет к прерыванию после того, как ваше ядро ​​получит ресурс. Запросы помещаются в очередь и обслуживаются в том порядке, в котором они были сделаны. Семафорный запрос - это атомная операция.

Консистенция кэша - это еще одна проблема, и в некоторых случаях вам может потребоваться резервное копирование и обновление кэша. Но это очень специфичная для кэша реализация. С 6487/8 нам нужно было сделать это на нескольких операциях.