This is a small post about a specific pattern for cancellation in the Rustprogramming language. The pattern is simple and elegant, but it’s ratherdifficult to come up with it by yourself.
To be able to stop a worker, we need to have one in the first place! So, let’simplement a model program.
The task is to read the output line-by-line, sending these lines to another threadfor processing (echoing the line back, with ❤️).My solution looks like this:
Now that we have a worker, let’s add a new requirement.
When the user types stop, the worker (but not the program itself) should be halted.
How can we do this? The most obvious way is to add a new variant, Stop, to the Msgenum, and break out of the worker’s loop:
This works, but only partially:
We can add more code to fix the panic, but let’s stop for a moment and tryto invent a more elegant way to stop the worker. The answer will be below thisbeautiful Ukiyo-e print :-)
The answer is: the cleanest way to cancel something in Rust is to drop it.For our task, we can stop the worker by dropping the Sender:
Note the interesting parts of the solution:
no need to invent an additional message type,
the Sender is stored inside an Option, so that we candrop it with the .take method,
the Option forces us to check if the worker is alivebefore sending a message.
More generally, previously the worker had two paths for termination: a normaltermination via the Stop message and an abnormal termination after a panicin recv (which might happen if the parent thread panics and drops the Sender).Now there is a single code path for both cases. That means we can be surer that ifsomething somewhere dies with a panic then the shutdown will proceed in anorderly fashion, it is not a special case anymore.
The only thing left to make this ultimately neat is to replace a hand-written while letwith a for loop: