ComponentsThreadChannel::recv()

ThreadChannel::recv

(PHP 8.6+, True Async 1.0)

php
public ThreadChannel::recv(?Completable $cancellationToken = null): mixed

Receives the next value from the channel. This is a blocking operation — the calling thread is blocked if no values are currently available in the channel.

  • For a buffered channel, recv() returns immediately if the buffer contains at least one value. If the buffer is empty, the thread blocks until a sender places a value.
  • For an unbuffered channel (capacity = 0), recv() blocks until another thread calls send().

If the channel is closed and the buffer still contains values, those values are returned normally. Once the buffer is drained and the channel is closed, recv() throws ThreadChannelException.

The received value is a deep copy of the original — modifications to the returned value do not affect the sender's copy.

Return values

The next value from the channel (mixed).

Errors

  • Throws Async\ThreadChannelException if the channel is closed and the buffer is empty.

Examples

Example #1 Receiving values produced by a worker thread

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $channel = new ThreadChannel(5);

    $worker = spawn_thread(function() use ($channel) {
        for ($i = 1; $i <= 5; $i++) {
            $channel->send($i * 10);
        }
        $channel->close();
    });

    // Receive all values — blocks when buffer is empty
    try {
        while (true) {
            echo $channel->recv(), "\n";
        }
    } catch (\Async\ThreadChannelException) {
        echo "All values received\n";
    }

    await($worker);
});

Example #2 Consumer thread draining a shared channel

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $channel = new ThreadChannel(20);

    // Producer: fills the channel from one thread
    $producer = spawn_thread(function() use ($channel) {
        foreach (range('a', 'e') as $letter) {
            $channel->send($letter);
        }
        $channel->close();
    });

    // Consumer: drains the channel from another thread
    $consumer = spawn_thread(function() use ($channel) {
        $collected = [];
        try {
            while (true) {
                $collected[] = $channel->recv();
            }
        } catch (\Async\ThreadChannelException) {
            // buffer drained and channel closed
        }
        return $collected;
    });

    await($producer);
    $result = await($consumer);
    echo implode(', ', $result), "\n"; // "a, b, c, d, e"
});

Example #3 Receiving from an unbuffered channel

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $channel = new ThreadChannel(); // unbuffered

    $sender = spawn_thread(function() use ($channel) {
        // Blocks here until the main thread calls recv()
        $channel->send(['task' => 'compress', 'file' => '/tmp/data.bin']);
    });

    // Main coroutine (thread) calls recv() — unblocks the sender
    $task = $channel->recv();
    echo "Got task: {$task['task']} on {$task['file']}\n";

    await($sender);
});

See also