Многопоточность на нескольких ядрах / процессорах - PullRequest
0 голосов
/ 31 октября 2019

Я понял, что если блокировка и разблокировка мьютекса является атомарной операцией, она может защитить критическую часть кода в случае однопроцессорной архитектуры. Любой поток, который будет запланирован первым, сможет "заблокировать" мьютекс в одной операции машинного кода. Но как мьютексы хороши, когда потоки работают на нескольких ядрах? (Где разные потоки могут работать одновременно на разных «ядрах» одновременно). Кажется, я не могу понять идею, как многопоточная программа будет работать без каких-либо тупиков или состояний гонки на нескольких ядрах?

Ответы [ 3 ]

1 голос
/ 31 октября 2019

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

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

0 голосов
/ 31 октября 2019

Общий ответ:

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


Подробный ответ:

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

Всего с двумя атомарными операциями atomic_or и atomic_and,можно реализовать блокировку. Например, подумайте о

int atomic_or ( int * addr, int val )

Атомно вычисляет *addr = *addr | val и возвращает старое значение *addr до выполнения вычисления. Если *lock == 0 и несколько потоков вызывают atomic_or(lock, 1), то только один из них получит 0 в качестве результата;только первый поток, чтобы выполнить эту операцию. Все остальные темы получают 1 в результате. Один поток, получивший 0, является победителем, он имеет блокировку, все остальные потоки регистрируются на событие и переходят в спящий режим.

Поток победителя теперь имеет эксклюзивный доступ к разделу, следующему за atomic_or, он может выполнить желаемую работу и, как только это будет сделано, он просто снова снимает блокировку (atomic_and(lock, 0)) и генерирует системное событие, что блокировка теперь снова доступна.

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

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

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

0 голосов
/ 31 октября 2019

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

Мьютекс - это структура данных, которая находится в системной памяти. Любой поток, имеющий доступ, может прочитать эту позицию в памяти, независимо от того, в каком потоке или ядре он работает. Неважно, выполняется ли ваш код на ядре 1 или 20, он по-прежнему может читать текущее состояниеlock.

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

...