Функции par_unseq и «векторизация небезопасны» - PullRequest
4 голосов
/ 05 января 2020

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

Я получаю общее представление: par_unseq политика выполнения позволяет компилятору выполнять векторизацию, поэтому один поток может чередовать инструкции между различными экземплярами функций. Из-за этого использование чего-то вроде мьютекса может привести к тупику из-за переупорядочения команд.

Но как быть с алгоритмами Atom c без блокировки, такими как compare_exchange l oop? Или алгоритмы Atom c без ожидания, такие как механизм подсчета ссылок Atomi c?

Сначала я предположил, что все будет в порядке. Однако в объяснении на cppreference.com говорится:

Неупорядоченные политики выполнения являются единственным случаем, когда вызовы функций не последовательны по отношению друг к другу, то есть они могут чередоваться. Во всех других ситуациях в C ++ они имеют неопределенную последовательность (не могут чередоваться). Из-за этого пользователям не разрешается выделять или освобождать память, приобретать мьютексы, использовать не-lockfree специализации std :: atomi c или вообще выполнять любые небезопасные операции векторизации при использовании этих политик (функции векторизации небезопасных). те, которые синхронизируются с другой функцией, например, std::mutex::unlock синхронизируются с следующей std::mutex::lock)

Это сбивает с толку, потому что на с одной стороны, он говорит, что операции без блокировки std::atomic - это нормально, но с другой стороны, он говорит, что небезопасная векторизация - это любая функция, которая синхронизируется с другой функцией. Термин «синхронизируется с» в стандарте C ++ означает не только мьютексы - это означает любую операцию atomi c, которая синхронизируется с другой, например, загрузку atomi c с использованием std::memory_order_acquire, которая синхронизируется с atomi c хранить с помощью std::memory_order_release. Такие операции могут быть без блокировки или без ожидания, но все же синхронизироваться друг с другом, чтобы гарантировать упорядочение между потоками.

Так что можно использовать, например, операции получения / освобождения с блокировкой без std::atomic переменных (если используемый алгоритм фактически не блокируется, т.е. продвижение вперед гарантируется хотя бы одним потоком)? Или par_unseq запрещает ЛЮБУЮ синхронизацию вообще (т. Е. Могут безопасно использоваться только расслабленные операции Atom c)?

Ответы [ 2 ]

2 голосов
/ 05 января 2020

cppreference.com не является официальным. Фактический стандарт C ++ говорит ничего об использовании атомики внутри неупорядоченного алгоритма и просто исключает все небезопасные векторизации операции. Цель состоит в том, чтобы устранить любые зависимости между итерациями.

Неупорядоченная политика выполнения позволяет выполнять несколько итераций одновременно в одном потоке . Это нарушает обычную семантику и гарантии продвижения вперед и может привести к тупику. Например, CAS l oop, ожидающий результата предыдущей итерации, может никогда не завершиться sh, поскольку программа переупорядочена для выполнения 8 таких циклов с последующей векторной операцией.

int a[100]{};
std::atomic<int> busy = 0;
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int& x) {
    int expected;
    while (!busy.compare_exchange_strong(expected = 0, 1)) {} // might deadlock
    x++;
    busy = 0;
});

На практике Вы не хотели бы смешивать векторизованный код с доступом atomi c, так как первый используется в критичном для производительности коде, а второй очень медленный. Компилятор векторизации, вероятно, также не сможет векторизовать такой код.

0 голосов
/ 05 января 2020

В нем говорится, что вы не можете использовать операции без блокировки std::atomic. Он не говорит, что вы можете использовать операции без блокировки std::atomic, и при этом он не говорит, что вы не можете использовать операции без блокировки std::atomic операции.

Таким образом, существует возможность использования операций без блокировки std::atomic, но вам все равно необходимо убедиться, что они соответствуют другим критериям (например, не синхронизируются с другой функцией).

...