Thread overview
Thread/Task cancellation
Jul 28
Gjiergji
July 28

I am coming from a C# background. I understood that there is no async/await equivalent in D (except fibers which are not suitable for multi threading), but if I am using threads, what is the D idiom to implement cancellation?

Usually a long running thread looks like this (in C#):

try
{
   while (!cancellationToken.IsCancellationRequested)
   {
      //do some work
      await SomethingAsync(cancellationToken);
      //do some other work
      await Task.Delay(TimeSpan.FromSeconds(5000), cancellationToken);
   }
}
catch (OperationCancelledException e) when (e.Token == cancellationToken)
{
   //someone cancelled any of the await calls above, we can swallow it or log it
}

The question is how do I pass a cancellationToken to the calls from the loop in order to terminate them before completion. For example, I learnt about Thread.sleep in phobos, but I cannot pass a cancellation token in order to cancel it before the intended sleep duration.

Thx.

July 28

On Friday, 28 July 2023 at 18:17:18 UTC, Gjiergji wrote:

>

I am coming from a C# background. I understood that there is no async/await equivalent in D (except fibers which are not suitable for multi threading), but if I am using threads, what is the D idiom to implement cancellation?

Usually a long running thread looks like this (in C#):

try
{
   while (!cancellationToken.IsCancellationRequested)
   {
      //do some work
      await SomethingAsync(cancellationToken);
      //do some other work
      await Task.Delay(TimeSpan.FromSeconds(5000), cancellationToken);
   }
}
catch (OperationCancelledException e) when (e.Token == cancellationToken)
{
   //someone cancelled any of the await calls above, we can swallow it or log it
}

The question is how do I pass a cancellationToken to the calls from the loop in order to terminate them before completion. For example, I learnt about Thread.sleep in phobos, but I cannot pass a cancellation token in order to cancel it before the intended sleep duration.

Thx.

You could use a thread to check if the token has been sent via message passing, and when it is sent, throw an exception, like this:

import std.concurrency;

Tid tid;

void foo()
{
    try
    {
        tid = spawn(&bar);
        // do stuff
    }
    catch(Exception e)
    {
        // ...
    }
}

void bar()
{
    bool terminate = false;
    terminate = receiveOnly!bool();
    if(terminate)
    {
        throw new Exception("Thread terminated");
    }
}

void main()
{
    spawn(&foo);
    // ...
    if(needsToTerminateFooForSomeReason)
        tid.send(true);
    // ...
}

This does however, terminate with signal 11 upon sending the terminate signal, and I'm not sure why.

July 28

On Friday, 28 July 2023 at 18:52:59 UTC, Ruby The Roobster wrote:

>

On Friday, 28 July 2023 at 18:17:18 UTC, Gjiergji wrote:

>

I am coming from a C# background. I understood that there is no async/await equivalent in D (except fibers which are not suitable for multi threading), but if I am using threads, what is the D idiom to implement cancellation?

Usually a long running thread looks like this (in C#):

try
{
   while (!cancellationToken.IsCancellationRequested)
   {
      //do some work
      await SomethingAsync(cancellationToken);
      //do some other work
      await Task.Delay(TimeSpan.FromSeconds(5000), cancellationToken);
   }
}
catch (OperationCancelledException e) when (e.Token == cancellationToken)
{
   //someone cancelled any of the await calls above, we can swallow it or log it
}

The question is how do I pass a cancellationToken to the calls from the loop in order to terminate them before completion. For example, I learnt about Thread.sleep in phobos, but I cannot pass a cancellation token in order to cancel it before the intended sleep duration.

Thx.

[SNIP]

>

You could use a thread to check if the token has been sent via message passing, and when it is sent, throw an exception, like this:

>

This does however, terminate with signal 11 upon sending the terminate signal, and I'm not sure why.

Ignore my above code, Here is something that should work:

import std.concurrency;

void foo()
{
    try
    {
        auto tid = spawnLinked(&bar);
        ownerTid.send(tid);
        // do stuff
        // ...

        auto c  = receiveTimeout(0.msecs, (ubyte a) {}); // Since bar is linked, this will throw an exception when bar terminates
    }
    catch(Exception e)
    {
        // Do whatever with the exception message, but it terminates the function execution.
    }
}

void bar()
{
    bool terminate = false;
    terminate = receiveOnly!bool();
}

void main()
{
    spawn(&foo);
    Tid tid = receiveOnly!Tid();
    // ...
    if(needsToTerminateFooForSomeReason)
        tid.send(true);
    // ...
}

This is the only way I could think of doing this, since exceptions don't travel up the threads.