Нужен ли забор или барьер или что-то еще, когда блокировка / разблокировка мьютекса скрыты глубоко в вызовах функций?

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

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

Таким образом, pthread_mutex_lock и pthread_mutex_unlock неявно должны быть этими «барьерами». Что если у меня есть такой класс, который окутывает мой мьютекс?

class IMutex {
public:
virtual void lock() = 0;
virtual void unlock() = 0;
};

мне кажется, компилятор не будет знать, что я вызываю pthread_mutex_lock () внутри lock () и pthread_mutex_unlock () внутри unlock (), потому что все это виртуально удалено.

Это приведет к ошибкам? Нужно ли как-то вручную указывать барьеры?

6

Решение

Переупорядочение инструкций осуществляется на разных уровнях. Самый очевидный из них — это компилятор, а менее очевидный — это процессор (который на лету). Однако функции синхронизации почти всегда являются ограждением, которое предотвращает изменение порядка команд до и после ограждения.

Так что если ваш виртуальный lock звонки pthread_mutex_*() тогда ваши виртуальные функции содержат забор.

Итак, короткий ответ: нет, это не приведет к ошибкам.

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

Единственный раз, когда вам нужно знать о заборах, это когда вы не используете объекты параллелизма для выполнения синхронизации (например, использование bool вместо мьютекса).

6

Другие решения

Других решений пока нет …