最終更新日時: 2026年07月22日 16時08分23秒 (JST)
rotarymars が更新

履歴 編集

customization point object
<execution>

# std::execution::spawn(C++26)

    namespace std::execution {
      struct spawn_t { unspecified };
      inline constexpr spawn_t spawn{};
    }

## 概要

`spawn`は、入力Senderに対して非同期トークンスコープへの関連付けを試み、成功時に入力Senderを早期開始(eagerly start)させるSenderコンシューマである。

## 効果

説明用の式`sndr`, `token`, `env`を下記の通り定義する。

- `Sndr`型を`decltype((sndr))`、
- `Token`型を`remove_cvref_t<decltype((token))>`、
- `Env`型を`remove_cvref_t<decltype((env))>`とする。

`sender<Sndr>`, `scope_token<Token>`, `queryable<Env>`のいずれかを満たさないとき、呼び出し式`spawn(sndr, token, env)`は不適格となる。

そうでなければ、呼び出し式`spawn(sndr, token, env)`に対して、説明用の式`new_sender`を`token.wrap(sndr)`とし、`alloc`と`senv`を次の通りとする。

- 式`get_allocator(env)`が適格なとき、`alloc`を`get_allocator(env)`の結果、`senv`を式`env`とする。
- そうではなく、式`get_allocator(get_env(new_sender))`が適格なとき、`alloc`を`get_allocator(get_env(new_sender))`の結果、`senv`を式`JOIN-ENV(prop(get_allocator, alloc), env)`とする。
- そうではないとき、`alloc`を`allocator<void>()`、`senv`を式`env`とする。

呼び出し式`spawn(sndr, token, env)`は`void`型であり、次の効果をもつ。

- `alloc`を用いてメモリ確保し、`alloc`, `write_env(token.wrap(sndr), senv)`, `token`から`decltype(spawn-state(alloc, write_env(token.wrap(sndr), senv), token))`型のオブジェクト`o`を構築し、`o.run()`を呼び出す。いずれかのオブジェクト構築・破棄時に例外送出されたときは、確保されたメモリが解放される。

呼び出し式`spawn(sndr, token)`は、式`spawn(sndr, token, execution::env<>())`と等価である。

## 説明専用エンティティ

### クラス`spawn-state-base`

    namespace std::execution {
      struct spawn-state-base {                // exposition only
        virtual void complete() noexcept = 0;  // exposition only
      };
    }

### クラス`spawn-receiver`

    namespace std::execution {
      struct spawn-receiver {                  // exposition only
        using receiver_concept = receiver_tag;

        spawn-state-base* state;               // exposition only
        void set_value() && noexcept { state->complete(); }
        void set_stopped() && noexcept { state->complete(); }
      };
    }

### クラステンプレート`spawn-state`

    namespace std::execution {
      template<class Alloc, scope_token Token, sender Sender>
      struct spawn-state : spawn-state-base {                   // exposition only
        using op-t = connect_result_t<Sender, spawn-receiver>;  // exposition only

        spawn-state(Alloc alloc, Sender&& sndr, Token token);   // exposition only
        void complete() noexcept override;                      // exposition only
        void run() noexcept;                                    // exposition only

      private:
        using assoc-t =                                         // exposition only
          remove_cvref_t<decltype(declval<Token&>().try_associate())>;

        Alloc alloc;                                            // exposition only
        op-t op;                                                // exposition only
        assoc-t assoc;                                          // exposition only
      };
    }

    spawn-state(Alloc alloc, Sender&& sndr, Token token);

- 効果 : メンバ変数`alloc`を`std::move(alloc)`で、メンバ変数`assoc`を`token.try_associate()`で、メンバ変数`op`を下記で初期化する。

      connect(std::move(sndr), spawn-receiver(this))

    void run() noexcept;

- 効果 : 下記と等価

      if (assoc)
        start(op);
      else
        complete();

    void complete() noexcept override;

- 効果 ： 下記と等価

      auto assoc = std::move(this->assoc);
      {
        using traits = allocator_traits<Alloc>::template rebind_traits<spawn-state>;
        typename traits::allocator_type alloc(this->alloc);
        traits::destroy(alloc, this);
        traits::deallocate(alloc, this, 1);
      }

## 例

    #include <print>
    #include <execution>
    #include <utility>
    namespace ex = std::execution;

    int main()
    {
      // スレッドプール上の実行タスクを定義
      ex::scheduler auto sch = ex::get_parallel_scheduler();
      ex::sender auto sndr =
        ex::schedule(sch)
        | ex::then([](){ std::println("hello async"); });

      // 非同期スコープを定義
      ex::counting_scope scope;

      // タスクを早期開始させる
      std::println("spawn");
      ex::spawn(std::move(sndr), scope.get_token());

      // 非同期スコープを合流
      std::println("sync_wait");
      std::this_thread::sync_wait(scope.join());
    }

### 出力

    spawn
    hello async
    sync_wait

## バージョン

### 言語

- C++26

### 処理系

- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??

## 関連項目

- `execution::scope_token`
- `execution::spawn_future`

## 参照

- P3149R11 `async_scope` - Creating scopes for non-sequential concurrency
- P3815R1 Add `scope_association` concept to P3149
- P3923R0 Additional NB comment resolutions for Kona 2025, US 227-346, 229-347