tokio-rs / tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Home Page:https://tokio.rs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Tokio select! Macro Issue with Barrier

suxb201 opened this issue · comments

Version
tokio v1.37.0
tokio-macros v2.2.0 (proc-macro)

Platform
Darwin Kernel Version 23.0.0

Description
The Barrier implementation might be incrementing the state.generation field every time the select! is called.

I tried this code:

use tokio;
use std::sync::Arc;
use tokio::select;
use tokio::time::sleep;
use tokio::sync::Barrier;
use tokio::task::JoinSet;

#[tokio::main]
async fn main() {
    let barrier = Arc::new(Barrier::new(2));
    let mut tasks = JoinSet::new();
    tasks.spawn({
        let barrier = barrier.clone();
        async move {
            loop {
                sleep(std::time::Duration::from_secs(1)).await;
                barrier.wait().await;
            }
        }
    });
    tasks.spawn(async move {
        let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
        loop {
            select! {
                _ = interval.tick() => {
                    println ! ("interval tick");
                }
                _ = barrier.wait() => {
                    println ! ("barrier wait");
                }
            }
        }
    });
    for _ in 0..2 {
        tasks.join_next().await;
    }
}

I expected to see this happen:

interval tick
barrier wait
interval tick
barrier wait
interval tick
barrier wait
...

Instead, this happened:

interval tick
barrier wait
barrier wait
interval tick
barrier wait
barrier wait
interval tick
barrier wait
barrier wait
...

Thank you for reporting this. Barriers are not cancel safe, so you can't use them in a tokio::select! like that. Unfortunately, fixing this would take a breaking change.

I have opened #6494 to document this issue.