Tokio ctrl_c handler doesn't fire

This code (tokio part) is taken verbatim from tokio's webpage. This is working example.

use tokio::{
    sync::mpsc::{UnboundedReceiver, UnboundedSender},
async fn tokio_ctrl_c(shutdown_send: UnboundedSender<()>) {
    // ... spawn application as separate task ...
    // application uses shutdown_send in case a shutdown was issued from inside
    // the application
    match signal::ctrl_c().await {
        Ok(()) => {
        Err(err) => {
            eprintln!("Unable to listen for shutdown signal: {}", err);
            // we also shut down in case of error

async fn main() -> anyhow::Result<()> {
    let (shutdown_send, mut shutdown_recv) = tokio::sync::mpsc::unbounded_channel::<()>();

    let handle = tokio::spawn(async move {
        // Do some async work

        main_rusb(&mut shutdown_recv);

        "return value"

fn main_rusb(shutdown_recv: &mut UnboundedReceiver<()>) {
    loop {
        if let Ok(_) = shutdown_recv.try_recv() {

Unfortunately if it is not run from main thread this behaves in a way that Ctrl+C doesn't get triggered. Could somebody explain why and how to fix it?

When you returned from main, the shutdown process immediately started, and the runtime attempted to kill all tasks. It succeeded in killing the tokio_ctrl_c task, but since your other task is blocking the thread, it can't be killed.

To fix this:

  1. Stop blocking the thread. Read this article to see how.
  2. Make sure that you don't return from main until you want to exit the program.
1 Like

Thanks, I suspected that.
Best regards