Skip to content

Commit d5e4d19

Browse files
authored
Merge 2019-02 LWG Motion 14
P1001R2 Target Vectorization Policies from Parallelism V2 TS to C++20 Fixes #2705.
2 parents 6da8552 + 6f6e577 commit d5e4d19

File tree

3 files changed

+94
-37
lines changed

3 files changed

+94
-37
lines changed

source/algorithms.tex

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,35 @@
313313
\end{itemize}
314314
\end{example}
315315

316+
\pnum
317+
A standard library function is \defn{vectorization-unsafe}
318+
if it is specified to synchronize with another function invocation, or
319+
another function invocation is specified to synchronize with it,
320+
and if it is not a memory allocation or deallocation function.
321+
\begin{note}
322+
Implementations must ensure that internal synchronization
323+
inside standard library functions does not prevent forward progress
324+
when those functions are executed by threads of execution
325+
with weakly parallel forward progress guarantees.
326+
\end{note}
327+
\begin{example}
328+
\begin{codeblock}
329+
int x = 0;
330+
std::mutex m;
331+
void f() {
332+
int a[] = {1,2};
333+
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) {
334+
std::lock_guard<mutex> guard(m); // incorrect: \tcode{lock_guard} constructor calls \tcode{m.lock()}
335+
++x;
336+
});
337+
}
338+
\end{codeblock}
339+
The above program may result in two consecutive calls to \tcode{m.lock()}
340+
on the same thread of execution (which may deadlock),
341+
because the applications of the function object are not guaranteed
342+
to run on different threads of execution.
343+
\end{example}
344+
316345
\rSec2[algorithms.parallel.user]{Requirements on user-provided function objects}
317346

318347
\pnum
@@ -378,6 +407,29 @@
378407
The invocations are not interleaved; see~\ref{intro.execution}.
379408
\end{note}
380409

410+
\pnum
411+
The invocations of element access functions in parallel algorithms invoked with
412+
an execution policy object of type \tcode{execution::unsequenced_policy}
413+
are permitted to execute in an unordered fashion
414+
in the calling thread of execution,
415+
unsequenced with respect to one another in the calling thread of execution.
416+
\begin{note}
417+
This means that multiple function object invocations
418+
may be interleaved on a single thread of execution,
419+
which overrides the usual guarantee from \ref{intro.execution}
420+
that function executions do not overlap with one another.
421+
\end{note}
422+
The behavior of a program is undefined if
423+
it invokes a vectorization-unsafe standard library function
424+
from user code
425+
called from a \tcode{execution::unsequenced_policy} algorithm.
426+
\begin{note}
427+
Because \tcode{execution::unsequenced_policy} allows
428+
the execution of element access functions
429+
to be interleaved on a single thread of execution,
430+
blocking synchronization, including the use of mutexes, risks deadlock.
431+
\end{note}
432+
381433
\pnum
382434
The invocations of element access functions in parallel algorithms invoked with
383435
an execution policy object of type \tcode{execution::parallel_policy}
@@ -439,7 +491,7 @@
439491

440492
\pnum
441493
The invocations of element access functions in parallel algorithms invoked with
442-
an execution policy of type \tcode{execution::parallel_unsequenced_policy} are
494+
an execution policy object of type \tcode{execution::parallel_unsequenced_policy} are
443495
permitted to execute
444496
in an unordered fashion in unspecified threads of execution, and
445497
unsequenced with respect to one another within each thread of execution.
@@ -451,48 +503,28 @@
451503
This means that multiple function object invocations may be interleaved
452504
on a single thread of execution,
453505
which overrides the usual guarantee from \ref{intro.execution}
454-
that function executions do not interleave with one another.
506+
that function executions do not overlap with one another.
455507
\end{note}
456-
Since \tcode{execution::parallel_unsequenced_policy} allows
508+
The behavior of a program is undefined if
509+
it invokes a vectorization-unsafe standard library function
510+
from user code
511+
called from a \tcode{execution::parallel_unsequenced_policy} algorithm.
512+
\begin{note}
513+
Because \tcode{execution::parallel_unsequenced_policy} allows
457514
the execution of element access functions
458515
to be interleaved on a single thread of execution,
459516
blocking synchronization, including the use of mutexes, risks deadlock.
460-
Thus, the synchronization with \tcode{execution::parallel_unsequenced_policy}
461-
is restricted as follows:
462-
A standard library function is \defn{vectorization-unsafe}
463-
if it is specified to synchronize with another function invocation, or
464-
another function invocation is specified to synchronize with it, and
465-
if it is not a memory allocation or deallocation function.
466-
Vectorization-unsafe standard library functions may not be invoked by user code
467-
called from \tcode{execution::parallel_unsequenced_policy} algorithms.
468-
\begin{note}
469-
Implementations must ensure
470-
that internal synchronization inside standard library functions
471-
does not prevent forward progress
472-
when those functions are executed
473-
by threads of execution with weakly parallel forward progress guarantees.
474517
\end{note}
475-
\begin{example}
476-
\begin{codeblock}
477-
int x = 0;
478-
std::mutex m;
479-
int a[] = {1,2};
480-
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) {
481-
std::lock_guard<mutex> guard(m); // incorrect: \tcode{lock_guard} constructor calls \tcode{m.lock()}
482-
++x;
483-
});
484-
\end{codeblock}
485-
The above program may result in two consecutive calls to \tcode{m.lock()}
486-
on the same thread of execution (which may deadlock),
487-
because the applications of the function object are not guaranteed
488-
to run on different threads of execution.
489-
\end{example}
518+
519+
\pnum
490520
\begin{note}
491-
The semantics of the \tcode{execution::parallel_policy} or
492-
the \tcode{execution::parallel_unsequenced_policy} invocation
521+
The semantics of invocation with
522+
\tcode{execution::unsequenced_policy},
523+
\tcode{execution::parallel_policy}, or
524+
\tcode{execution::parallel_unsequenced_policy}
493525
allow the implementation to fall back to sequential execution
494-
if the system cannot parallelize an algorithm invocation
495-
due to lack of resources.
526+
if the system cannot parallelize an algorithm invocation,
527+
e.g., due to lack of resources.
496528
\end{note}
497529

498530
\pnum

source/support.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@
588588
\tcode{<unordered_set>} \\ \rowsep
589589
\defnlibxname{cpp_lib_exchange_function} & \tcode{201304L} &
590590
\tcode{<utility>} \\ \rowsep
591-
\defnlibxname{cpp_lib_execution} & \tcode{201603L} &
591+
\defnlibxname{cpp_lib_execution} & \tcode{201902L} &
592592
\tcode{<execution>} \\ \rowsep
593593
\defnlibxname{cpp_lib_filesystem} & \tcode{201703L} &
594594
\tcode{<filesystem>} \\ \rowsep

source/utilities.tex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19059,10 +19059,14 @@
1905919059
// \ref{execpol.parunseq}, parallel and unsequenced execution policy
1906019060
class parallel_unsequenced_policy;
1906119061

19062+
// \ref{execpol.unseq}, unsequenced execution policy
19063+
class unsequenced_policy;
19064+
1906219065
// \ref{execpol.objects}, execution policy objects
1906319066
inline constexpr sequenced_policy seq{ @\unspec@ };
1906419067
inline constexpr parallel_policy par{ @\unspec@ };
1906519068
inline constexpr parallel_unsequenced_policy par_unseq{ @\unspec@ };
19069+
inline constexpr unsequenced_policy unseq{ @\unspec@ };
1906619070
}
1906719071
\end{codeblock}
1906819072

@@ -19156,6 +19160,26 @@
1915619160
\tcode{terminate()} shall be called.
1915719161
\end{itemdescr}
1915819162

19163+
\rSec2[execpol.unseq]{Unsequenced execution policy}
19164+
19165+
\indexlibrary{\idxcode{execution::unsequenced_policy}}%
19166+
\begin{itemdecl}
19167+
class execution::unsequenced_policy { @\unspec@ };
19168+
\end{itemdecl}
19169+
19170+
\pnum
19171+
The class \tcode{unsequenced_policy} is an execution policy type
19172+
used as a unique type to disambiguate parallel algorithm overloading and
19173+
indicate that a parallel algorithm's execution may be vectorized,
19174+
e.g., executed on a single thread using instructions
19175+
that operate on multiple data items.
19176+
19177+
\pnum
19178+
During the execution of a parallel algorithm with
19179+
the \tcode{execution::unsequenced_policy} policy,
19180+
if the invocation of an element access function exits via an uncaught exception,
19181+
\tcode{terminate()} shall be called.
19182+
1915919183
\rSec2[execpol.objects]{Execution policy objects}
1916019184

1916119185
\indexlibrary{\idxcode{seq}}%
@@ -19168,6 +19192,7 @@
1916819192
inline constexpr execution::sequenced_policy execution::seq{ @\unspec@ };
1916919193
inline constexpr execution::parallel_policy execution::par{ @\unspec@ };
1917019194
inline constexpr execution::parallel_unsequenced_policy execution::par_unseq{ @\unspec@ };
19195+
inline constexpr execution::unsequenced_policy execution::unseq{ @\unspec@ };
1917119196
\end{itemdecl}
1917219197

1917319198
\begin{itemdescr}

0 commit comments

Comments
 (0)