P2079R3 proposes a shared system execution context
A common execution context could let C++ libraries share a thread pool without claiming isolated resources. The revised proposal makes context lifetime explicit and leaves runtime replacement as an open design question.
Giving every library a private thread pool can make local parallelism compete with the rest of an application. P2079R3, dated July 14, proposes a system execution context whose objects share an underlying execution facility. Lee Howes, Ruslan Arutyunyan, and Michael Voss design it around the proposed sender-and-scheduler model while deliberately avoiding a fixed thread count.
Sharing is the central contract. Constructing another context object must not imply constructing another private pool. Conversely, two context objects do not provide task isolation. Work submitted through one can consume resources needed by another. A common facility solves one resource-management problem while making that lack of isolation explicit.
RAII is the part of C++ I find most convincing, so the proposal's lifetime rules interest me as much as its scheduler interface. A handle that schedules work is not necessarily the owner that keeps the execution environment alive. P2079R3 names both roles and assigns different obligations to them.
A context is an explicit lifetime boundary
The proposed system_context is neither copyable nor movable. Construction may initialize the shared underlying context if necessary. Its get_scheduler operation provides a scheduler that refers back to this explicit object, even though the underlying execution resources are shared more broadly.
The context must outlive the work launched on it. The proposal says destroying it with outstanding work calls std::terminate. Schedulers obtained from it must also be gone before destruction. Outstanding scheduler handles at that point produce undefined behaviour under the proposed contract.
Those rules prevent a shared global pool from making every local lifetime question disappear. The pool's existence and the validity of a scheduler's reference to a particular context are separate matters. The explicit object gives the application a boundary at which unfinished work or surviving handles indicate an error.
The scheduler itself is copyable and movable, but cannot be independently default-constructed. It comes from a context. Its handle need not outlive work already submitted through it, which differs from the stronger lifetime requirement on the context. This distinction permits temporary scheduling handles without making execution depend on their continued existence.
Parallel progress does not promise isolation
The design provides parallel forward progress and does not let an application control a fixed level of parallelism. The authors want the same interface to fit a static pool, an operating-system pool, or a configured implementation for a single-threaded environment. Requiring a particular number of worker threads would constrain those implementation choices.
The proposed max_concurrency operation reports a maximum the context may support. It is not a snapshot of currently running threads, and the paper permits it to return the maximum value of size_t. A caller should therefore avoid reading it as a precise allocation of workers to one context instance.
Sharing also means a blocking design cannot assume unrelated context objects provide independent workers. The paper explicitly warns that one instance can consume the shared pool and block another's progress. Algorithms need to rely on the stated progress guarantees instead of inferring concurrency from the number of context objects constructed.
My preference is for a standard facility to state this limitation directly. An interface that silently creates independent pools would hide application-wide resource use. A shared implementation is useful only when its users understand that shared capacity does not imply fairness or task isolation guarantees beyond the proposal's contract.
Driving work becomes implementation-specific
Compared with P2079R2, R3 removes execute_all and execute_chunk. Those operations had exposed ways to drive execution, but the authors conclude they impose particular requirements on the underlying context. The new revision discusses customization instead of standardizing those driving operations.
The single-threaded case explains the problem. Some environment must donate its only thread to execution. In a user-interface program, that thread may already drive an event loop. A generic drive function can become an awkward second loop rather than a portable abstraction over the actual environment.
The authors recommend leaving the driving mechanism unspecified and allowing it to accompany the selected implementation. This is a recommendation in an active proposal, not a resolved standard customization interface. The paper asks whether the choice improves portability and discusses both sides of that question.
Replacement has unresolved costs
R3 examines replacement at link time, compile time, or runtime. Link-time replacement can be application-global but needs a binary interface and type erasure. Compile-time replacement is simpler in some respects but risks inconsistent settings among separately compiled objects. Runtime replacement can use familiar interfaces but raises initialization-order and dispatch costs.
The authors do not choose a general replacement mechanism. They want customization to be possible while asking how much the standard should specify. Priorities are likewise deferred, with scheduler-level and receiver-query approaches discussed as alternatives. These open questions are part of the proposal's status.
The concrete contribution is a shared execution facility with explicit context and scheduler lifetimes. A program using that model must drain work before destroying its context and must not assume each context buys a separate set of threads. The remaining customization discussion determines how that contract can fit operating-system pools and environments whose only execution thread already belongs to an event loop.