C++创建多线程的方法总结

news/2024/5/14 11:02:13/文章来源:https://blog.csdn.net/weixin_44120785/article/details/128990201

        下个迭代有个任务很有趣,用大量的线程去访问一个接口,直至其崩溃为止,这就需要多线程的知识,这也不是什么难事,总结一下C++中的多线程方法:std、boost、pthread、windows api。

目录

一、多线程预备知识

二、C++11 std::thread 

2.1 创建线程

2.2 线程管理

2.3 传递参数

2.4 线程间通信 

2.4.1 使用共享变量和互斥量(互斥锁):

2.4.2 使用共享内存

2.5 其他线程相关信息

三、boost多线程库

四、POSIX线程(Linux&Unix) 

五、 Windows线程库

5.1 进程使用

5.2 进程通信


一、多线程预备知识

        多线程本质是将程序的运行拆分为部分,每个线程都有自己的执行上下文,包括它的程序计数器,寄存器和栈,并且它们独立地执行,互不干扰。我们必须要明确的是多线程的实现依赖硬件条件:多线程需要多核处理器。多核处理器可以同时执行多个线程,因此多线程可以利用多核处理器的多个内核来实现更快的处理速度和更高的性能。通过使用多核处理器,可以把多个线程并行执行,从而实现更高的性能和更快的处理速度。

        比如说,在图像处理应用中,如果使用多核处理器,可以把图像处理任务分成多个独立的部分,并使用多个线程分别执行每个部分。每例如,线程 1 可以处理图像的颜色校正,线程 2 可以处理图像的缩放,线程 3 可以处理图像的旋转等。由于每个线程都可以同时执行,因此处理速度比单线程处理要快得多。需要注意的是,在这种情况下,还需要考虑线程间的同步和通信,以确保线程之间的数据一致性。

二、C++11 std::thread 

2.1 创建线程

#include <iostream>
#include <thread>void foo()
{std::cout << "Hello from thread" << std::endl;
}int main()
{std::thread t1(foo);t1.join();return 0;
}

        在上面的代码中,通过 std::thread t1(foo) 创建了一个新线程,并在新线程中执行了函数 foo。 

2.2 线程管理

#include <iostream>
#include <thread>void foo()
{std::cout << "Hello from thread" << std::endl;
}int main()
{std::thread t1(foo);t1.join();t1.detach();return 0;
}

        在上面的代码中,通过调用 t1.join() 可以等待线程 t1 结束,并通过调用 t1.detach() 可以分离线程 t1,使线程在后台运行。 

   std::thread::detach() 方法是分离线程的方法,通过调用 detach() 方法,可以让线程在后台独立运行,不需要等待线程结束即可返回。与调用 join() 方法不同,分离的线程不受父线程的控制,因此如果父线程结束,分离的线程不会因此结束。请注意,分离的线程一旦开始执行,它将独立运行,不受任何控制,因此不能在父线程中等待它的结束或者通过其他方式获取其结果。如果需要等待线程结束,请使用 join() 方法。

        分离线程的主要作用是让线程在后台独立运行,不需要等待线程结束即可返回。这样可以在不需要等待线程结束的情况下,在父线程中执行其他任务,从而提高程序的效率。

2.3 传递参数

#include <iostream>
#include <thread>void foo(int x)
{std::cout << "Hello from thread, x = " << x << std::endl;
}int main()
{std::thread t1(foo, 10);t1.join();return 0;
}

        在上面的代码中,通过在创建线程时传递参数 10,并在函数 foo 中读取参数,实现了在线程中传递参数的功能。

2.4 线程间通信 

2.4.1 使用共享变量和互斥量(互斥锁):

#include <iostream>
#include <thread>
#include <mutex>int g_num = 0;
std::mutex g_num_mutex;void print_num() {while (true) {g_num_mutex.lock();if (g_num >= 100) {g_num_mutex.unlock();break;}std::cout << "Thread " << std::this_thread::get_id() << ": " << g_num++ << std::endl;g_num_mutex.unlock();}
}int main() {std::thread t1(print_num);std::thread t2(print_num);t1.join();t2.join();return 0;
}

        我们定义了一个全局变量g_num,两个线程分别运行print_num函数。print_num函数不断地对g_num变量进行读写操作,并使用互斥量g_num_mutex对该变量进行加锁。这样可以确保在每次读写操作时,不会有其他线程访问g_num变量。如果g_num的值已经大于等于100,则表示线程退出。最后主线程调用join函数,等待其他线程退出。

 2.4.2 使用共享内存

#include <iostream>
#include <thread>
#include <string>using namespace std;string message;void write_message()
{message = "Hello World";
}void read_message()
{cout << message << endl;
}int main()
{thread t1(write_message);thread t2(read_message);t1.join();t2.join();return 0;
}

2.5 其他线程相关信息

  • std::thread::hardware_concurrency():返回当前系统支持的最大线程数。

  • std::thread::native_handle():返回线程的原生句柄,在不同的平台中可能不同。

  • std::thread::joinable():判断线程是否可以被 join,如果线程已经结束或者被分离,则返回 false。

  • std::thread::join():等待线程结束,直到线程结束才返回。

  • std::thread::detach():分离线程,使线程可以在后台运行,并且不需要等待其结束。

  • std::thread::get_id() :返回线程ID。

三、boost多线程库

官方文档:

Chapter 38. Thread 4.8.0 - 1.73.0

        Boost 库中的 boost::thread 类可以方便地创建和管理多线程。以下是一个使用 Boost 库中的 boost::thread 类创建多线程的简单示例:

#include <iostream>
#include <boost/thread.hpp>void worker_thread()
{std::cout << "Worker thread is running" << std::endl;
}int main()
{boost::thread worker(worker_thread);std::cout << "Main thread is running" << std::endl;worker.join();return 0;
}

四、POSIX线程(Linux&Unix) 

        C++ POSIX 线程(pthread)库可以帮助您在 C++ 中创建和管理多线程。下面是一个创建和启动一个新线程的示例代码:

#include <pthread.h>
#include <iostream>void *thread_func(void *arg)
{std::cout << "Thread started with argument: " << *((int *)arg) << std::endl;return NULL;
}int main()
{pthread_t thread_id;int arg = 42;// 创建新线程int result = pthread_create(&thread_id, NULL, thread_func, &arg);if (result != 0) {std::cerr << "Error: pthread_create() failed" << std::endl;return 1;}// 等待线程结束result = pthread_join(thread_id, NULL);if (result != 0) {std::cerr << "Error: pthread_join() failed" << std::endl;return 1;}return 0;
}

        这段代码中,pthread_create 函数用于创建一个新线程,并启动它。第一个参数是一个指向线程 ID 的指针,第二个参数指定了线程的属性,通常为 NULL,第三个参数是线程函数的地址,最后一个参数是传递给线程函数的参数。

   pthread_join 函数等待线程结束,第一个参数是线程 ID,第二个参数是接收线程返回值的指针,通常为 NULL

五、 Windows线程库

5.1 进程使用

        下面是使用Windows API创建线程并打印数字并获取重要的线程信息的代码示例:

#include <iostream>
#include <Windows.h>DWORD WINAPI ThreadFunction(LPVOID lpParam)
{// 获取当前线程IDDWORD threadId = GetCurrentThreadId();std::cout << "Thread ID: " << threadId << std::endl;// 获取线程传入的参数int threadParam = *(int*)lpParam;for (int i = 0; i < threadParam; i++){std::cout << i << std::endl;}return 0;
}int main()
{int num = 10;// 创建线程HANDLE hThread = CreateThread(NULL, 0, ThreadFunction, &num, 0, NULL);// 等待线程结束WaitForSingleObject(hThread, INFINITE);// 关闭线程句柄CloseHandle(hThread);return 0;
}

5.2 进程通信

        在 Windows API 中,可以使用 CreateThread 函数创建线程,以下是通过共享变量实现线程间通信的代码示例:

#include <Windows.h>
#include <iostream>DWORD WINAPI ThreadFunction1(LPVOID lpParam)
{int* sharedVariable = (int*)lpParam;while (true){if (*sharedVariable == 0){std::cout << "Thread 1: sharedVariable = " << *sharedVariable << std::endl;*sharedVariable = 1;}}return 0;
}DWORD WINAPI ThreadFunction2(LPVOID lpParam)
{int* sharedVariable = (int*)lpParam;while (true){if (*sharedVariable == 1){std::cout << "Thread 2: sharedVariable = " << *sharedVariable << std::endl;*sharedVariable = 0;}}return 0;
}int main()
{int sharedVariable = 0;HANDLE hThread1 = CreateThread(NULL, 0, ThreadFunction1, &sharedVariable, 0, NULL);HANDLE hThread2 = CreateThread(NULL, 0, ThreadFunction2, &sharedVariable, 0, NULL);WaitForMultipleObjects(2, &hThread1, TRUE, INFINITE);CloseHandle(hThread1);CloseHandle(hThread2);return 0;
}

    在主函数中,我们调用了 CreateThread 函数创建了两个线程,将共享变量 sharedVariable 的地址作为参数传入。线程 1 和线程 2 都通过判断共享变量的值来实现通信,它们每当共享变量的值变化时都会输出当前的值。  

在这个例子中,WaitForMultipleObjects函数将等待两个线程hThread1和hThread2完成,并且要求等待所有事件对象完成,因此参数bWaitAll的值为TRUE。并且dwMilliseconds的值为INFINITE,所以等待时间是无限的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_256835.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot实现ChatGPT-QQ机器人

概述 近期ChatGPT火爆全球&#xff0c;在其官方网站上也列举了非常全面的应用案例&#xff0c;仅仅上线两个月活跃用户数已经达到1亿&#xff0c;成为历史上用户数增长最快的面向消费者的应用 快速体验 OpenAI官网对外提供了标准的 API 接口&#xff0c;可以通过HTTP请求进行…

简单的密码加密

用户的密码必须被加密后再存储到数据库, 否则就存在用户账号安全问题用户使用的原始密码通常称之为"原文"或"明文", 经过算法的运算, 得到的结果通常称之为"密文"在处理密码加密时, 不可以使用任何加密算法, 因为所有加密算法都是可以被逆向运算…

centos学习记录

遇到的问题及其解决办法 centos7安装图形化界面 yum groupinstall ‘X Window System’ yum groupinstall -y ‘GNOME Desktop’ 安装完成后输入init 5进入图形化界面 centos7安装vmware-tools 第一步卸载open-vm-tools 输入命令 yum remove open-vm-tools 输入命令 reboot 在…

微前端基础

一、什么是微前端 微前端是一种软件架构&#xff0c;可以将前端应用拆解成一些更小的能够独立开发部署的微型应用&#xff0c;然后再将这些微应用进行组合使其成为整体应用的架构模式。微前端架构类似于组件架构&#xff0c;但不同的是&#xff0c;组件不能独立构建和发布&…

大数据时代的小数据神器 - asqlcell

自从Google发布了经典的MapReduce论文&#xff0c;以及Yahoo开源了Hadoop的实现&#xff0c;大数据这个词就成为了一个行业的热门。在不断提高的机器性能和各种层出不穷的工具框架加持下&#xff0c;数据分析开始从过去的采样抽查变成全量整体&#xff0c;原先被抽样丢弃的隐藏…

网络安全实验室7.综合关

7.综合关 1.渗透测试第一期 url&#xff1a;http://lab1.xseclab.com/base14_2d7aae2ae829d1d5f45c59e8046bbc54/ 进入忘记密码页面&#xff0c;右键查看源码&#xff0c;发现一个手机号 解题思路&#xff1a;通过给admin用户绑定13388758688手机号码&#xff0c;然后再进行…

使用vue3,vite,less,flask,python从零开始学习硅谷外卖(16-40集)

严正声明&#xff01; 重要的事情说一遍&#xff0c;本文章仅供分享&#xff0c;文章和代码都是开源的&#xff0c;严禁以此牟利&#xff0c;严禁侵犯尚硅谷原作视频的任何权益&#xff0c;我知道学习编程的人各种各样的心思都有&#xff0c;但这不是你对开源社区侵权的理由&am…

【算法题解】15. 设计最小栈

这是一道 中等难度 的题。 题目来自&#xff1a;leetcode 题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在 常数时间 内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void p…

驱动 | Linux | NVMe 不完全总结

本文主要参考这里 1’ 2 的解析和 linux 源码 3。 此处推荐一个可以便捷查看 linux 源码的网站 bootlin 4。 更新&#xff1a;2022 / 02 / 11 驱动 | Linux | NVMe 不完全总结NVMe 的前世今生从系统角度看 NVMe 驱动NVMe CommandPCI 总线从架构角度看 NVMe 驱动NVMe 驱动的文件…

详细解读503服务不可用的错误以及如何解决503服务不可用

文章目录1. 问题引言2. 什么是503服务不可用错误3 尝试解决问题3.1 重新加载页面3.2 检查该站点是否为其他人关闭3.3 重新启动设备3.3 联系网站4. 其他解决问的方法1. 问题引言 你以前遇到过错误503吗&#xff1f; 例如&#xff0c;您可能会收到消息&#xff0c;如503服务不可…

三种方式查看linux终端terminal是否可以访问外网ping,curl,wget

方法1&#xff1a;ping注意不要用ping www.google.com.hk来验证&#xff0c;因为有墙&#xff0c;墙阻止了你接受网址发回的响应数据。即使你那啥过&#xff0c;浏览器都可以访问Google&#xff0c;terminal里面也是无法得到响应 百度在墙内&#xff0c;所以可以正常拿到响应信…

sklearn降维算法1 - 降维思想与PCA实现

目录1、概述1.1 维度概念2、PCA与SVD2.1 降维实现2.2 重要参数n_components2.2.1 案例&#xff1a;高维数据的可视化2.2.2 最大似然估计自选超参数2.2.3 按信息量占比选超参数1、概述 1.1 维度概念 shape返回的结果&#xff0c;几维几个方括号嵌套 特征矩阵特指二维的 一般来…

truffle 创建测试合约并部署到测试网络

1、npm 安装truffle npm install -g truffle2、创建truffle项目 mkdir imooc-on-blockchain-truffle && cd imooc-on-blockchain-truffle3、初始化truffle目录&#xff0c;会生成如下几个目录 contracts 存放.sol合约文件migrations 部署脚本目录test 测试文件目录t…

【GlobalMapper精品教程】045:空间分析工具(2)——相交

GlobalMapper提供的空间分析(操作)的方法有:交集、并集、单并集、差异、对称差集、相交、重叠、接触、包含、等于、内部、分离等,本文主要讲述相交工具的使用。 文章目录 一、实验数据二、符号化设置三、相交运算四、结果展示五、心灵感悟一、实验数据 加载配套实验数据(…

分布式之分布式事务V2

写在前面 本文一起来看下分布式环境下的事务问题&#xff0c;即我们经常听到的分布式事务问题。想要解决分布式事务问题&#xff0c;需要使用到分布式事务相关的协议&#xff0c;主要有2PC即两阶段提交协议&#xff0c;TCC&#xff08;try-confirm-cancel&#xff09;&#xf…

html的表单标签(form)

目录标题1、表单标签主要有三大类&#xff1a;2、表单标签中常见的属性3、例子代码及结果4、注意&#xff1a;5、表单中特殊的属性表单标签可以用来数据交互&#xff0c;而前面学的六个标签只能发送不能接收。 表单标签的作用就是数据交互1、表单标签主要有三大类&#xff1a; …

ImageMagick任意文件读取漏洞(CVE-2022-44268)

0x00 前提 前几天爆出一个 ImageMagick 漏洞 &#xff0c;可以造成一个任意文件读取的危害比较可观&#xff0c;最近有时间来复现学习一下 主要是影响的范围很大&#xff0c;很多地方都有这个问题&#xff0c;需要来学习一下 0x01 介绍 ImageMagick 是一个免费的开源软件套…

SpringMVC:拦截器(12)

拦截器1. 拦截器概念2. 拦截器入门案例2.1 环境准备2.2 拦截器开发步骤1: 创建拦截器类步骤2: 配置拦截器类步骤3: SpringMVC添加SpringMvcSupport包扫描和interceptor包扫描步骤4: 简化SpringMvcSupport的编写5 测试3. 拦截器参数解析&#xff08;了解&#xff09;3.1 前置处理…

【Call for papers】SIGCOMM-2023(CCF-A/计算机网络/2023年2月15日截稿)

ACM SIGCOMM is the flagship annual conference of the ACM Special Interest Group on Data Communication (SIGCOMM). ACM SIGCOMM 2023, the 37th edition of the conference series, will be held in New York City, US, September 10 - 14, 2023. 文章目录1.会议信息2.时…

Redis集群搭建(主从、哨兵、分片)

1.单机安装Redis 首先需要安装Redis所需要的依赖&#xff1a; yum install -y gcc tcl然后将课前资料提供的Redis安装包上传到虚拟机的任意目录&#xff1a; 例如&#xff0c;我放到了/tmp目录&#xff1a; 解压缩&#xff1a; tar -xzf redis-6.2.4.tar.gz解压后&#xff1…