|
313 | 313 | \end{itemize}
|
314 | 314 | \end{example}
|
315 | 315 |
|
| 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 | + |
316 | 345 | \rSec2[algorithms.parallel.user]{Requirements on user-provided function objects}
|
317 | 346 |
|
318 | 347 | \pnum
|
|
378 | 407 | The invocations are not interleaved; see~\ref{intro.execution}.
|
379 | 408 | \end{note}
|
380 | 409 |
|
| 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 | + |
381 | 433 | \pnum
|
382 | 434 | The invocations of element access functions in parallel algorithms invoked with
|
383 | 435 | an execution policy object of type \tcode{execution::parallel_policy}
|
|
439 | 491 |
|
440 | 492 | \pnum
|
441 | 493 | 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 |
443 | 495 | permitted to execute
|
444 | 496 | in an unordered fashion in unspecified threads of execution, and
|
445 | 497 | unsequenced with respect to one another within each thread of execution.
|
|
451 | 503 | This means that multiple function object invocations may be interleaved
|
452 | 504 | on a single thread of execution,
|
453 | 505 | 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. |
455 | 507 | \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 |
457 | 514 | the execution of element access functions
|
458 | 515 | to be interleaved on a single thread of execution,
|
459 | 516 | 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. |
474 | 517 | \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 |
490 | 520 | \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} |
493 | 525 | 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. |
496 | 528 | \end{note}
|
497 | 529 |
|
498 | 530 | \pnum
|
|
0 commit comments