如何循环线程句柄并在完成后加入另一个循环?

2024-04-26

我有一个程序,它在循环中创建线程,并检查它们是否已完成并清理它们(如果已完成)。请参阅下面的最小示例:

use std::thread;

fn main() {    

    let mut v = Vec::<std::thread::JoinHandle<()>>::new();
    for _ in 0..10 {
        let jh = thread::spawn(|| {
            thread::sleep(std::time::Duration::from_secs(1));
        });
        v.push(jh);
        for jh in v.iter_mut() {
            if jh.is_finished() {
                jh.join().unwrap();
            }
        } 
    }
}

这给出了错误:

error[E0507]: cannot move out of `*jh` which is behind a mutable reference
    --> src\main.rs:13:17
     |
13   |                 jh.join().unwrap();
     |                 ^^^------
     |                 |  |
     |                 |  `*jh` moved due to this method call
     |                 move occurs because `*jh` has type `JoinHandle<()>`, which does not implement the `Copy` trait
     |
note: this function takes ownership of the receiver `self`, which moves `*jh`
    --> D:\rust\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\std\src\thread\mod.rs:1461:17
     |
1461 |     pub fn join(self) -> Result<T> {

我怎样才能让借用检查员允许这样做?


JoinHandle::join实际上consumes连接句柄。iter_mut()然而,仅借用向量的元素并使向量保持活动状态。因此你的JoinHandles 只是借用的,并且您不能对借用的对象调用消费方法。

您需要做的是在迭代向量时获取元素的所有权,以便随后可以使用它们join()。这是通过使用实现的into_iter()代替iter_mut().

第二个错误是你(可能不小心)写了这两个for彼此内部循环,但它们应该是独立的循环。

第三个问题稍微复杂一些。你不能check如果线程已完成,然后按照您的方式加入它。因此我删除了is_finished()现在检查一下,然后再进一步讨论这个问题。

这是您的固定代码:

use std::thread;

fn main() {
    let mut v = Vec::<std::thread::JoinHandle<()>>::new();
    for _ in 0..10 {
        let jh = thread::spawn(|| {
            thread::sleep(std::time::Duration::from_secs(1));
        });
        v.push(jh);
    }

    for jh in v.into_iter() {
        jh.join().unwrap();
    }
}

对已完成的线程做出反应

这个比较难。如果你只是想等到all其中已经完成,上面的代码就是要走的路。

但是,如果您have要立即对已完成的线程做出反应,您基本上必须设置某种事件传播。您不想一遍又一遍地循环所有线程,直到它们全部完成,因为这就是所谓的空闲等待并且消耗大量的计算能力。

因此,如果要实现这一目标,必须解决两个问题:

  • join()消耗JoinHandle(),这会留下不完整的Vec of JoinHandles。这是不可能的,所以我们需要包装JoinHandle实际上可以部分地从向量中剥离出来的类型,例如Option.
  • 我们需要一种方法向主线程发出信号,表明新的子线程已完成,以便主线程不必不断迭代线程。

总而言之,实施起来非常复杂且棘手。

这是我的尝试:

use std::{
    thread::{self, JoinHandle},
    time::Duration,
};

fn main() {
    let mut v: Vec<Option<JoinHandle<()>>> = Vec::new();
    let (send_finished_thread, receive_finished_thread) = std::sync::mpsc::channel();

    for i in 0..10 {
        let send_finished_thread = send_finished_thread.clone();

        let join_handle = thread::spawn(move || {
            println!("Thread {} started.", i);

            thread::sleep(Duration::from_millis(2000 - i as u64 * 100));

            println!("Thread {} finished.", i);

            // Signal that we are finished.
            // This will wake up the main thread.
            send_finished_thread.send(i).unwrap();
        });
        v.push(Some(join_handle));
    }

    loop {
        // Check if all threads are finished
        let num_left = v.iter().filter(|th| th.is_some()).count();
        if num_left == 0 {
            break;
        }

        // Wait until a thread is finished, then join it
        let i = receive_finished_thread.recv().unwrap();
        let join_handle = std::mem::take(&mut v[i]).unwrap();
        println!("Joining {} ...", i);
        join_handle.join().unwrap();
        println!("{} joined.", i);
    }

    println!("All joined.");
}

重要的

这段代码只是一个演示。它会陷入僵局如果其中一个线程出现恐慌。但这表明这个问题有多么复杂。

可以通过使用下降防护装置来解决这个问题,但我认为这个答案已经足够复杂了;)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何循环线程句柄并在完成后加入另一个循环? 的相关文章

随机推荐

  • Ruby 使用 JSON 序列化结构

    我正在尝试将一个简单的结构序列化为 JSON 它工作正常 但我无法让它从 JSON 创建该结构的实例 我正在尝试这样做 require rubygems require json Person Struct new name age jso
  • python print() 函数实际上是做什么的?

    我正在看这个question https stackoverflow com questions 1979171 how can i escape xff xfe to a readable string并开始想知道什么是print实际上确
  • java中.this和.class的含义

    假设我们有一个类名称 Home 有什么区别主页 this and 家庭班 它们指的是什么 主页 this Home this指的是当前实例Home class 该表达式的正式术语似乎是合格了这个 http java sun com docs
  • 如果ViewData有ViewBag,为什么TempData没有TempBag?

    为什么 TempData 没有像 ViewData 那样的动态字典对象 之所以没有 是因为没有人费心去实施它 但这是很容易做到的 例如 作为扩展方法 不幸的是 NET 尚不支持扩展属性 因此您无法完全获得您可能希望的语法 public cl
  • 重新格式化双向条形图以匹配示例

    我生成了这个条形图 使用此代码 s level margins fluid margins vp Volume 0 0 1L 0 718 0 690 2L 0 501 0 808 5L 0 181 0 920 MAP 0 0 64 0 43
  • C 中每个块复制一个文件块

    我试图将文件分成 x 个大小为 y 以字节为单位 的块 以便我可以单独复制每个块 我怎样才能做到这一点 尝试使用fread http www manpagez com man 3 fread char buffer ysize fread
  • 使用数据表中的“selectAll”按钮搜索后选择所有可见行

    我已经初始化了一个具有 id 的数据表example像这样 var table example DataTable aaSorting 4 asc select true dom Bfrtip buttons excelHtml5 exte
  • 当更新可用时,手动安装的 apk(不是从 Play 商店)会收到通知吗?

    我想在平板电脑上安装 apk 知道怎么做 我的平板电脑会收到来自 Play 商店的通知吗 该更新已在 Play 商店中准备就绪 我应该安装它吗 仅当满足以下两个条件时 您才会收到更新 在 Google Play 已安装的应用程序 选项卡中看
  • Flash 影片的 Div Z-Index 问题

    我有两个简单的 HTML div 一个包含 flash 电影 另一个 div 包含简单文本 现在我的问题是我必须将文本 div 放到 flash 电影 div 上 我正在做的是将两个 div 的位置设置为 CSS 中的 Absolute 并
  • 如何为 SonarQube 扫描配置 Jenkins 管道

    我正在尝试为我的项目配置詹金斯管道 但这里缺少一些东西 如果有人可以指出我做错了什么 下面是管道脚本 node stage SonarQube analysis requires SonarQube Scanner 2 8 def scan
  • 协议缓冲区和 UTF-8

    编码方案 多操作系统和 Endian nes 的历史导致了对所有形式的字符串数据 即所有字母表 进行编码方面的混乱 因此 协议缓冲区仅处理其字符串类型中的 ASCII 或 UTF 8 并且我看不到任何接受 C wstring 的多态重载 那
  • 出现错误:User 类型的对象在 django python 中不可 JSON 序列化

    我是 django python 的新手 当我尝试从 3 个表获取数据时 出现错误Object of type User is not JSON serializable 任何人都可以帮我解释为什么我会收到此错误吗 在这里我添加了我的vie
  • 关于指针的c/c++问题(双指针)

    自从我学习 c 和 c 课程以来已经有一段时间了 我对 c 指针很好奇 我将在我的示例中使用 new 关键字 即使我知道 malloc 是 C 方式 我总是记得我的老师总是强迫我们使用指针 她永远不会接受数组的作业 她向我们证明 当您使用指
  • 使用页内 JSON 初始化 AngularJS $resource

    我正在使用 AngularJS 的 resource 来获取和更新对象 为了节省页面加载时的往返 我将 JSON 对象放在页面上的变量中 如何使用此数据初始化 resource 而不是调用 get 您可以使用new创建使用以下命令创建的资源
  • 在 asp.net mvc url 中格式化查询字符串的最佳方法?

    我注意到 如果您通过 asp net mvc 发送查询字符串路由值 您最终会将所有空格编码为 20 因为我希望将空格转换为 号 所以覆盖此格式的最佳方法是什么 我正在考虑也许使用自定义 Route 对象或派生自 IRouteHandler
  • 设计具有多个 id 的 RESTful 服务

    我正在设计一个 RESTful 服务 就是列出一组数据 主要问题是该集合没有合理的单一标识符 在系统的知识范围内也不能轻易地计算出特定的集合 因此 似乎不可能有 GET items identifier 服务 我确实有所请求的每个元素的 i
  • 融合表查询

    我有一个非常大的融合表 现在 我想根据用户需求进行查询 我的用户界面应该有一个下拉框来选择列的名称 另一个下拉框用于选择查询条件 gt user1225902 您需要在页面加载期间调用onLoad函数 我有同样的问题
  • 休息。球衣。如何以编程方式选择返回类型:JSON 或 XML?

    我有两个问题 1 我可以创建吗one类 使用 JAXB 注释对其进行注释 用于 XML 支持 并在中声明web xml
  • 为什么 Visual Studio 2008 中删除了在新 ATL 项目中使用属性的选项?

    这是来自 MSDN 评论的文本 根据 ATL Internals 2ed 一书 属性的使用已被弃用 不应在新的 ATL 项目中使用 但为什么 在 ATL 中 这些属性是编译器的技巧 它们不像 C 中的属性那样是平台的核心部分 它们的调试也比
  • 如何循环线程句柄并在完成后加入另一个循环?

    我有一个程序 它在循环中创建线程 并检查它们是否已完成并清理它们 如果已完成 请参阅下面的最小示例 use std thread fn main let mut v Vec