>
>
>
V1011. Function execution could be defe…


V1011. Function execution could be deferred. Consider specifying execution policy explicitly.

Анализатор обнаружил использование функции 'std::async', поведение которой может отличаться от того, которое было задумано программистом. 'std::async' принимает в качестве аргументов функцию, аргументы функции и, опционально, флаг, который влияет на политику вызова 'std::async'. Возвращаемым значением 'std::async' является 'std::future', значение которого будет выставлено по завершению функции.

Поведение 'std::async', зависит от переданных флагов следующим образом:

1) 'std::launch::async' - будет немедленно создан объект класса 'thread', с функцией и её аргументами в качестве аргументов нового потока. Т.е. 'std::async' инкапсулирует создание потока, получение 'std::future' и предоставляет однострочную запись для выполнения такого кода.

2) 'std::launch::deferred' - поведение функции поменяется, т.к. никакого асинхронного вызова не произойдёт. Вместо исполнения функции в новом потоке, она, вместе с аргументами, будет сохранена в 'std::future', чтобы быть вызванными позже. Это позже наступит тогда, когда кто-либо вызовет метод 'get' или 'wait' на 'future', которое вернул 'std::async'. При этот вызываемый объект выполнится в потоке, который вызывал 'get/wait'! Это поведение есть ни что иное, как отложенный вызов функции.

3) Флаг не выставлен (std::launch::async | std::launch::deferred ) - в этом случае будет выбрано одно из двух поведений описанных выше. Какое из двух? Неизвестно и зависит от имплементации.

Если используется функция 'std::async' без указания политики, то используется как раз третий случай. Чтобы избежать возможной неизвестности, анализатор выявляет такие случаи использования функции.

Future<int> foo = std::async(MyFunction, args...);

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

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

Future<int> foo = std::async(launch::async, MyFunction, args...)

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки при работе с многопоточными примитивами (интерфейсами запуска потоков на выполнение, синхронизации и обмена данными между потоками и пр.).

Данная диагностика классифицируется как: