#How to abort a tokio task in a loop

8 messages · Page 1 of 1 (latest)

high zinc
#

I have a tokio::JoinSet with n tasks. Tasks look like something like this:

async fn task(some_data : MyStruct, shared : Arc<Mutex<HashMap<String,String>>>) -> bool {
    if some_data.condition() {
        loop {
            if !shared.lock().unwrap().contains_key(some_data.x) {
                _ = tokio::time::sleep(Duration::from_secs(1)).await;
            }
            else {
                break;
            }
        }
    }
// rest of the code
}```

I then spawn the tasks and process them like this:

```rs
while let Some(success) = set.join_next().await {
    match success {
        Ok(success) => {
            if !success {
                set.shutdown().await;
                print_something();
                return false;
            }
        }
        // ...
    }
}

All the tasks that don't satisfy the condition() and thus don't enter the loop, get aborted. All the tasks that enter the loop are never aborted, and are stuck in an infinite loop of checking and sleeping. The shutdown().await never ends and the program doesn't exit. How do I abort them? I've tried tokio::select but didnt have much luck either there.

nova root
#

The issue is that the predicate of an if is kept around for the entire if-else statement, so it's actually sleeping while holding the lock. Put it before the if:

async fn task(some_data: MyStruct, shared: Arc<Mutex<HashMap<String, String>>>) -> bool {
    if some_data.condition() {
        loop {
            let contains = shared.lock().unwrap().contains_key(some_data.x);
            if !contains {
                tokio::time::sleep(Duration::from_secs(1)).await;
            } else {
                break;
            }
        }
    }
    // rest of the code
}
high zinc
#

i have now done that, but it didnt help. the outcome is the same.

nova root
#

then you're probably holding the lock elsewhere across an await

high zinc
#

its possible, ill look for that

nova root
#

Also that first thing I said was wrong, it only keeps the predicate around in if let, not normal boolean if.

#

Clippy should be able to tell you when you hold a mutex lock across an await.

high zinc
#

i've fixed my problem. i was using std::sync::Mutex instead of tokio::Mutex.