C++ 并发编程之std::find的并发版本

devtools/2025/1/19 15:56:26/

在C++中,std::find 是一个用于顺序查找容器中特定元素的算法。为了提高性能,我们可以设计并实现一个并行版本的 std::find,以便在多核处理器上并行执行查找操作。基本思想是将容器中的元素划分为若干块,每个块由一个单独的线程处理,并使用原子变量来确保只有一个线程返回找到的结果。

基本思想

  1. 任务划分:将容器中的元素划分成多个子范围(块),每个子范围由一个线程处理。任务划分的粒度可以根据容器的规模和处理器的核心数进行调整。
  2. 线程执行:每个线程独立处理分配给它的子范围,查找目标元素。如果某个线程找到了目标元素,它会将结果存储在一个原子变量中,并通知其他线程停止查找。
  3. 等待同步:在所有线程完成其任务后,主线程等待所有线程完成,然后返回找到的结果。

实现代码

我们可以使用 C++11 的 std::thread 和 std::atomic 来实现并行版本的 std::find。为了简化实现,我们可以使用 std::vector 来管理线程,并使用 std::atomic<bool> 来控制线程是否需要继续查找。

#include <iostream>
#include <vector>
#include <thread>
#include <algorithm>
#include <atomic>
#include <iterator>// 并行版本的 std::find
template<typename Iterator, typename T>
Iterator parallel_find(Iterator first, Iterator last, const T& value) {const unsigned long length = std::distance(first, last);// 如果没有元素,直接返回 lastif (length == 0) {return last;}// 获取系统支持的并发线程数const unsigned long max_threads = std::thread::hardware_concurrency();const unsigned long num_threads = std::min(max_threads != 0 ? max_threads : 2, length);// 每个线程处理的元素数量const unsigned long block_size = length / num_threads;std::vector<std::thread> threads(num_threads - 1);std::atomic<bool> found(false);std::vector<Iterator> results(num_threads, last);// 启动线程for (unsigned long i = 0; i < num_threads - 1; ++i) {Iterator block_start = first + i * block_size;Iterator block_end = block_start + block_size;threads[i] = std::thread([block_start, block_end, &value, &found, &results, i]() {for (Iterator it = block_start; it != block_end && !found.load(); ++it) {if (*it == value) {results[i] = it;found.store(true);return;}}});}// 主线程处理最后一个块Iterator block_start = first + (num_threads - 1) * block_size;for (Iterator it = block_start; it != last && !found.load(); ++it) {if (*it == value) {results[num_threads - 1] = it;found.store(true);break;}}// 等待所有线程完成std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));// 返回找到的结果for (auto result : results) {if (result != last) {return result;}}return last;
}int main() {std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 使用并行版本的 std::findauto result = parallel_find(v.begin(), v.end(), 7);if (result != v.end()) {std::cout << "Found " << *result << " at position " << std::distance(v.begin(), result) << std::endl;} else {std::cout << "Not found" << std::endl;}return 0;
}

代码说明

  1. 任务划分

    • length 是容器中元素的总数。
    • max_threads 是系统支持的并发线程数,num_threads 是我们实际使用的线程数(不超过元素数量)。
    • block_size 是每个线程处理的元素数量。
  2. 线程执行

    • 我们创建了一个 std::vector<std::thread> 来存储所有线程。
    • 每个线程处理一个子范围 [block_start, block_end),并查找目标元素。如果在子范围内找到了目标元素,线程会将结果存储在 results 中,并设置 found 为 true,通知其他线程停止查找。
  3. 等待同步

    • 主线程通过 std::thread::join 等待所有子线程完成。
    • 主线程遍历 results,返回第一个找到的结果。

应用

并行版本的 std::find 可以用于需要在大规模数据中快速查找特定元素的场景,例如:

  1. 大规模数据处理

    • 例如,在图像处理中查找特定的像素值,在音频数据中查找特定的频率等。
  2. 数据库查询

    • 例如,在数据库中查找特定的记录,尤其是在大规模数据库中。
  3. 并行搜索算法

    • 例如,在并行版本的深度优先搜索(DFS)或广度优先搜索(BFS)中查找特定的节点。

总结

通过实现并行版本的 std::find,我们可以在多核处理器上并行执行查找操作,从而提高程序的性能。代码中展示了如何将容器中的元素划分为多个子范围,并使用多个线程分别处理这些子范围。这种技术可以广泛应用于需要高效查找大规模数据的场景。


http://www.ppmy.cn/devtools/151850.html

相关文章

批量清理docker 容器日志

在日常开发过程中docker容器可能会有很大的日志占用空间&#xff0c;尝尝需要定期清理。下面提供查看容器日志大小和清理日志的一种解决方式 效果图 查看容器日志 bash docker_log_size.sh清理日志 bash docker_clean_logs.sh脚本 docker_log_size.sh #!/bin/bash# 获取所…

idea本地jar包添加到项目的maven库 mvn install:install-file

背景 最近在开发项目中需要对接海康威视摄像头&#xff0c;进行视频、照片等数据的获取保存&#xff1b;海康提供的sdk的jar包是自己开发的&#xff0c;在maven库中是找不到的&#xff0c;在项目中需要手动指定jar包路径 <dependency><groupId>com.haikang</g…

蓝桥杯刷题第二天——背包问题

题目描述 有N件物品和一个容量是V的背包。每件物品只能使用一次。第i件物品的体积是Vi价值是Wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数&#xff0c;N&#xff0c;V&am…

游戏引擎学习第79天

当前任务回顾 我们目前的工作重点是碰撞检测的更新&#xff0c;特别是将游戏的世界表示方式扩展到三维空间。尽管游戏本身是二维的&#xff0c;但我们希望它能够在三维空间中处理更多的内容&#xff0c;以支持那些需要考虑高度的游戏元素&#xff0c;如楼层、台阶等。我们的目…

青少年CTF练习平台 文章管理系统(sqlmap使用os-shell找flag)PHP

题目 点击下一篇出现参数id&#xff0c;单引号报错 找到注入点启动sqlmap 用sqlmap的os-shell执行命令获取flag python sqlmap.py -u http://challenge.qsnctf.com:32372/?id1 --os-shell 执行命令查找flag find / -name flag* find / -name *flag 发现/flag目录&#xff0c…

如何在谷歌浏览器中设置自定义安全警告

随着网络环境的日益复杂&#xff0c;浏览器的安全问题也愈发引人关注。谷歌浏览器作为一款广泛使用的浏览器&#xff0c;其自定义安全警告功能为用户提供了更加个性化和安全的浏览体验。本文将详细介绍如何在谷歌浏览器中设置自定义安全警告&#xff0c;帮助用户更好地保护自己…

【C++】揭秘类与对象的内在机制(核心卷之深浅拷贝与拷贝构造函数的奥秘)

文章目录 一、前置知识---深浅拷贝1. 浅拷贝2. 深拷贝 1. 拷贝构造函数1. 默认生成的拷贝构造函数能干什么&#xff1f;2. 怎么写拷贝构造函数 前景提要&#xff1a;该篇文章的内容接上一篇&#xff0c;希望大家可以先学习上一篇文章讲到的构造函数和析构函数&#xff0c;否则可…

认识软件测试 - 软实力面试题

目录 1. 什么是测试 1.1 简单认识测试 1.2 为什么需要测试 1.3 软件测试的定义 2. 测试的岗位有哪些 2.1 面试题 [HR 面]: 测开和测试的区别是什么? 3. 软件测试 和 软件开发 3.1 测试和调试的区别 3.2 面试题: 走测试岗位为什么还要学开发知识? 4. 优秀软件测试人…