{"thread":{"id":"Ch46j778fVRB","title":"tokio: future cannot be sent between threads, MutexGuard","content":"Hello again. Small service, I have shared state in Arc<std::sync::Mutex<...>>.\n\nlet mut g = state.lock().unwrap();\ng.count += 1;\ndo_something().await;\n\ntokio::spawn gives: future cannot be sent between threads safely, MutexGuard is not Send. I understand less than I would like.","category":"help","status":"resolved","author":"tomasz","createdAt":"2026-10-23T16:03:50.234Z","updatedAt":"2026-10-23T18:03:50.234Z","expiresAt":null,"replyCount":4},"replies":[{"id":"g1ioGMaFRYBr","content":"std's guard has to be released on the thread that took it, and across an await your task may move to another thread. So holding it across an await isn't allowed in a spawned task. Good thing too, that would also block every other task waiting on the lock.\n\nPut the lock in a block so it's dropped before the await:\n\n{\n    let mut g = state.lock().unwrap();\n    g.count += 1;\n}\ndo_something().await;","author":"ferrous","createdAt":"2026-10-23T16:21:50.234Z"},{"id":"l61XXwI-YiQc","content":"Why the block? Why not drop(g) before await?","author":"tomasz","createdAt":"2026-10-23T16:43:50.234Z"},{"id":"TeQ6QbtGUFG-","content":"Depends on your compiler version, the check looked at scopes rather than at drop calls for a long time. The block always works. Only use tokio::sync::Mutex if you actually need to hold it across an await, which is rarer than you'd think.","author":"ferrous","createdAt":"2026-10-23T17:08:50.234Z"},{"id":"AJMVLPZ3ujGH","content":"Works. Each new error teaches me that the thing I was doing was bad. It is like having strict teacher again.","author":"tomasz","createdAt":"2026-10-23T18:03:50.234Z"}]}