адвокат по языку — Может ли реализация C ++ теоретически распараллелить оценку двух аргументов функции?

Учитывая следующий вызов функции:

f(g(), h())

поскольку порядок вычисления аргументов функции не определен (насколько я знаю, все еще имеет место в C ++ 11), теоретически реализация может быть выполнена g() а также h() в параллели?

Такое распараллеливание могло только начаться g а также h известно, что это довольно тривиально (в наиболее очевидном случае — доступ только к локальным данным их тел), чтобы не создавать проблемы параллелизма, но, помимо этого ограничения, я не вижу ничего, что могло бы его запретить.

Итак, стандарт позволяет это? Даже если только по правилу «как будто»?

этот ответ, Манкарс утверждает иное; тем не менее, он не цитирует стандарт, и мое прочтение [expr.call] не выявил никакой очевидной формулировки.)

68

Решение

Требование исходит от [intro.execution]/15:

… При вызове функции … Каждая оценка в вызывающей функции (включая другие вызовы функций), которая иначе специально не упорядочена до или после выполнения тела вызываемой функции, неопределенно последовательность в отношении выполнения вызываемой функции [Сноска: Другими словами, выполнение функций не чередуется друг с другом.].

Так что любое исполнение тела g() должен быть определенным образом определен (то есть не перекрываться) с оценкой h() (так как h() является выражением в вызывающей функции).

Критическая точка здесь заключается в том, что g() а также h() оба функциональных вызова.

(Конечно, правило «как будто» означает, что возможность не может быть полностью исключена, но она никогда не должна происходить таким образом, чтобы это могло повлиять на наблюдаемое поведение программы. В лучшем случае такая реализация просто изменила бы характеристики производительности код.)

42

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

Пока вы не можете сказать, что компилятор делает для оценки этих функций, полностью зависит от компилятора. Очевидно, что оценка функций не может включать в себя какой-либо доступ к совместно используемым изменяемым данным, поскольку это может привести к гонкам данных. Основным руководящим принципом является принцип «как будто» и основные наблюдаемые операции, то есть доступ к volatile данные, операции ввода / вывода, доступ к элементарным данным и т. д. Соответствующий раздел — 1.9 [intro.execution].

16

Нет, если компилятор точно не знает, что g(), h()и все, что они называют, делает.

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

Это означает, что нужно пройтись по каждой функции и посмотреть, что именно они делают и / или вызвать, а затем проследить те функции и т. д. В общем случае это невозможно.

3

Простой ответ: когда функции последовательный, даже если неопределенно, нет никакой возможности для расы между двумя, что неверно, если они распараллелены. Даже пара однорядных «тривиальных» функций может это сделать.

void g()
{
*p = *p + 1;
}void h()
{
*p = *p - 1;
}

Если p это общее имя g а также hзатем последовательный вызов g а также h в любом порядке приведет к значению, указанному p не меняется Если они распараллелены, чтение *p и его присвоение может быть произвольно перемежено между двумя:

  1. g читает *p и находит значение 1.
  2. f читает *p а также находит значение 1.
  3. g пишет 2 в *p,
  4. f, все еще используя значение 1, которое он прочитал перед записью 0 в *p,

Таким образом, поведение отличается, когда они распараллелены.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector