Skip to content

Commit faad03c

Browse files
committed
P1001R2 Target Vectorization Policies from Parallelism V2 TS to C++20
Move the example in the added paragraph of [algorithms.parallel.defns] into a function, since statements cannot appear at namespace scope.
1 parent 6f34b05 commit faad03c

File tree

3 files changed

+87
-34
lines changed

3 files changed

+87
-34
lines changed

source/algorithms.tex

Lines changed: 61 additions & 33 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: lock_guard constructor calls 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,27 @@
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+
Since \tcode{execution::unsequenced_policy} allows
423+
the execution of element access functions
424+
to be interleaved on a single thread of execution,
425+
blocking synchronization, including the use of mutexes, risks deadlock.
426+
Thus, the synchronization with \tcode{execution::unsequenced_policy}
427+
is restricted as follows:
428+
vectorization-unsafe standard library functions may not be invoked
429+
by user code called from \tcode{execution::unsequenced_policy} algorithms.
430+
381431
\pnum
382432
The invocations of element access functions in parallel algorithms invoked with
383433
an execution policy object of type \tcode{execution::parallel_policy}
@@ -439,7 +489,7 @@
439489

440490
\pnum
441491
The invocations of element access functions in parallel algorithms invoked with
442-
an execution policy of type \tcode{execution::parallel_unsequenced_policy} are
492+
an execution policy object of type \tcode{execution::parallel_unsequenced_policy} are
443493
permitted to execute
444494
in an unordered fashion in unspecified threads of execution, and
445495
unsequenced with respect to one another within each thread of execution.
@@ -451,48 +501,26 @@
451501
This means that multiple function object invocations may be interleaved
452502
on a single thread of execution,
453503
which overrides the usual guarantee from \ref{intro.execution}
454-
that function executions do not interleave with one another.
504+
that function executions do not overlap with one another.
455505
\end{note}
456506
Since \tcode{execution::parallel_unsequenced_policy} allows
457507
the execution of element access functions
458508
to be interleaved on a single thread of execution,
459509
blocking synchronization, including the use of mutexes, risks deadlock.
460510
Thus, the synchronization with \tcode{execution::parallel_unsequenced_policy}
461511
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
512+
vectorization-unsafe standard library functions may not be invoked by user code
467513
called from \tcode{execution::parallel_unsequenced_policy} algorithms.
514+
515+
\pnum
468516
\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.
474-
\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}
490-
\begin{note}
491-
The semantics of the \tcode{execution::parallel_policy} or
492-
the \tcode{execution::parallel_unsequenced_policy} invocation
517+
The semantics of invocation with
518+
\tcode{execution::unsequenced_policy},
519+
\tcode{execution::parallel_policy}, or
520+
\tcode{execution::parallel_unsequenced_policy}
493521
allow the implementation to fall back to sequential execution
494-
if the system cannot parallelize an algorithm invocation
495-
due to lack of resources.
522+
if the system cannot parallelize an algorithm invocation,
523+
e.g., due to lack of resources.
496524
\end{note}
497525

498526
\pnum

source/support.tex

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

source/utilities.tex

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

18941+
// \ref{execpol.unseq}, unsequenced execution policy
18942+
class unsequenced_policy;
18943+
1894118944
// \ref{execpol.objects}, execution policy objects
1894218945
inline constexpr sequenced_policy seq{ @\unspec@ };
1894318946
inline constexpr parallel_policy par{ @\unspec@ };
1894418947
inline constexpr parallel_unsequenced_policy par_unseq{ @\unspec@ };
18948+
inline constexpr unsequenced_policy unseq{ @unspec@ };
1894518949
}
1894618950
\end{codeblock}
1894718951

@@ -19035,6 +19039,26 @@
1903519039
\tcode{terminate()} shall be called.
1903619040
\end{itemdescr}
1903719041

19042+
\rSec2[execpol.unseq]{Unsequenced execution policy}
19043+
19044+
\indexlibrary{\idxcode{execution::unsequenced_policy}}%
19045+
\begin{itemdecl}
19046+
class execution::unsequenced_policy { @\unspec@ };
19047+
\end{itemdecl}
19048+
19049+
\pnum
19050+
The class \tcode{unsequenced_policy} is an execution policy type
19051+
used as a unique type to disambiguate parallel algorithm overloading and
19052+
indicate that a parallel algorithm's execution may be vectorized,
19053+
e.g., executed on a single thread using instructions
19054+
that operate on multiple data items.
19055+
19056+
\pnum
19057+
During the execution of a parallel algorithm with
19058+
the \tcode{execution::unsequenced_policy} policy,
19059+
if the invocation of an element access function exits via an uncaught exception,
19060+
\tcode{terminate()} shall be called.
19061+
1903819062
\rSec2[execpol.objects]{Execution policy objects}
1903919063

1904019064
\indexlibrary{\idxcode{seq}}%
@@ -19047,6 +19071,7 @@
1904719071
inline constexpr execution::sequenced_policy execution::seq{ @\unspec@ };
1904819072
inline constexpr execution::parallel_policy execution::par{ @\unspec@ };
1904919073
inline constexpr execution::parallel_unsequenced_policy execution::par_unseq{ @\unspec@ };
19074+
inline constexpr execution::unsequenced_policy execution::unseq{ @\unspec@ };
1905019075
\end{itemdecl}
1905119076

1905219077
\begin{itemdescr}

0 commit comments

Comments
 (0)