Rust解决Bug错误“error: future cannot be sent between threads safely”

介绍:

在开发过程中,我们可能会遇到错误消息: "error: future cannot be sent between threads safely"。这个错误通常是由于使用了不可发送(not Send)的类型引起的,尤其是 std::sync::MutexGuard 类型。这意味着我们不能将一个互斥锁(mutex)在不同线程间进行传递,而 Tokio 运行时又允许任务在每个 .await 点之间在不同线程间移动。因此,我们需要重新组织代码以确保互斥锁的析构函数在 .await 之前运行,以避免出现此错误。

还有另外一种方案是使用 tokio::task::LocalSet。通过使用 LocalSet,你可以确保异步任务只在单个线程上运行,而不需要实现 Send。这对于需要任务始终在同一线程上访问特定资源的情况非常有用。

范例一:

下面我们提供了一个范例来说明可以解决该问题的正确代码和错误代码。

正确代码:

rust 复制代码
use std::sync::{Mutex, MutexGuard};

async fn ictester_main(mutex: &Mutex<i32>) {
    {
        let mut lock: MutexGuard<i32> = mutex.lock().unwrap();
        *lock += 1;
    } // 在这里,互斥锁的析构函数会在.await之前运行,并释放锁
 
    http_get_request_async().await;
}

错误代码:

rust 复制代码
use std::sync::{Mutex, MutexGuard};
 
async fn ictester_main(mutex: &Mutex<i32>) {
    let mut lock: MutexGuard<i32> = mutex.lock().unwrap();
    *lock += 1;
    drop(lock); // 这种方式是错误的
 
    http_get_request_async().await;
}

范例二:

另一种解决方案是使用 tokio::task::LocalSet。通过使用 LocalSet,你可以确保异步任务只在单个线程上运行,而不需要实现 Send。这对于需要任务始终在同一线程上访问特定资源的情况非常有用。

rust 复制代码
use tokio::task::LocalSet;

// ...

let mut local_set = LocalSet::new();
local_set.spawn_local(ictester_main(yourI32Param.clone()));

let out = local_set.await;

在上面的代码中,我们创建了一个 LocalSet,然后使用 spawn_local() 方法将异步任务 ictester_main() 添加到 LocalSet 中。这确保了该任务将在同一线程上运行,从而避免了错误:"error: future cannot be sent between threads safely"。

注意事项

  1. 在使用互斥锁(Mutex)时,务必在任务的关键点上正确释放锁。最佳实践是确保互斥锁的析构函数在.await之前运行,以确保锁被正确释放。可以通过在互斥锁的作用域内使用大括号来控制互斥锁的生命周期。
  2. 避免在异步任务中手动调用drop函数来释放互斥锁。手动调用drop函数会导致互斥锁被提前释放,可能会导致错误,因为互斥锁不应该在异步的上下文中手动释放。
  3. 当使用tokio::task::LocalSet来确保异步任务在同一线程上运行时,需要注意,该方式适用于在同一线程上访问特定资源的情况。

总结:

在解决 "error: future cannot be sent between threads safely" 类似的错误时,我们应该避免将不可发送类型引入跨线程的异步任务中。这可以通过确保互斥锁的析构函数在 .await 之前运行,或者使用 tokio::task::LocalSet 等方法来限制任务的运行范围。通过合理组织代码,我们可以避免这种错误,并确保程序的线程安全性。

除了通过重新组织代码以确保互斥锁在 .await 前释放以避免错误外,还可以使用 tokio::task::LocalSet 来限制异步任务的运行范围。这样可以确保任务始终在同一线程上运行,而无需实现 Send。根据具体情况选择适合的解决方案,以确保代码的正确性和线程安全性。

相关推荐
无敌最俊朗@19 分钟前
C++后端总览
开发语言
多喝开水少熬夜25 分钟前
堆相关算法题基础-java实现
java·开发语言·算法
7澄132 分钟前
Java 集合框架:List 体系与实现类深度解析
java·开发语言·vector·intellij-idea·集合·arraylist·linkedlist
mit6.8241 小时前
一些C++的学习资料备忘
开发语言·c++
Adellle1 小时前
Java中同步和异步的区别,以及阻塞和非阻塞的区别
java·开发语言
闲人编程1 小时前
用Python分析你的Spotify/网易云音乐听歌数据
开发语言·python·ai·数据分析·spotify·网易云·codecapsule
Js_cold1 小时前
(* MARK_DEBUG=“true“ *)
开发语言·fpga开发·debug·verilog·vivado
ALex_zry2 小时前
深入解析gRPC C++动态反射:实现Proto消息的智能字段映射
开发语言·c++
幸运小圣2 小时前
for...of vs for 循环全面对比【前端JS】
开发语言·前端·javascript
liu****2 小时前
12.线程同步和生产消费模型
linux·服务器·开发语言·c++·1024程序员节