Closing Channels in D Programming Language

In this example, we’ll demonstrate how to close channels and communicate completion to the channel’s receivers.

import std.stdio;
import std.concurrency;

void main()
{
    auto jobs = new Tid[5];
    auto done = new Tid;

    // Here's the worker thread. It repeatedly receives
    // from `jobs` with `receiveOnly!int()`. We use `receiveOnly`
    // because D doesn't have a special 2-value form of receive.
    // We use a try-catch block to handle the `OwnerTerminated`
    // exception, which is thrown when the channel is closed.
    spawn({
        try {
            while (true) {
                int j = receiveOnly!int();
                writeln("received job ", j);
            }
        } catch (OwnerTerminated e) {
            writeln("received all jobs");
            done.send(true);
        }
    });

    // This sends 3 jobs to the worker over the `jobs`
    // channel, then terminates it.
    for (int j = 1; j <= 3; j++) {
        jobs ~= spawn({
            send(thisTid, j);
            writeln("sent job ", j);
        });
    }

    foreach (job; jobs)
        prioritySend(job, thisTid);

    writeln("sent all jobs");

    // We await the worker using the synchronization approach.
    receiveOnly!bool();

    // In D, we don't have a direct way to check if a channel is closed.
    // Instead, we can use a try-catch block to attempt to receive from
    // the channel and catch the OwnerTerminated exception if it's closed.
    try {
        receiveOnly!int();
        writeln("received more jobs: true");
    } catch (OwnerTerminated e) {
        writeln("received more jobs: false");
    }
}

In this D version, we use the std.concurrency module to work with threads and message passing. D doesn’t have built-in channels like Go, so we use thread IDs (Tid) and message passing to simulate similar behavior.

The spawn function is used to create new threads, similar to goroutines in Go. We use send and receiveOnly functions for communication between threads.

D doesn’t have a direct equivalent to Go’s channel closing. Instead, we simulate this by terminating the owner thread, which causes an OwnerTerminated exception when other threads try to receive from it.

To run the program, save it as closing_channels.d and use the D compiler:

$ dmd -run closing_channels.d
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

This example demonstrates how to simulate channel closing in D using thread termination and exception handling. While the concepts are similar, the implementation differs due to D’s different concurrency model.