C++ 多线程笔记1 线程的创建

里面代码会用到的头文件

#include <iostream>
#include <string>
#include <memory>
#include <thread>
#include <vector>
#include <stdlib.h>
#include <cmath>
#include <chrono>
#include <ctime>

入门例子

void mytest()
{
std::cout<<"hello"<<'\n';
}
int main()
{
std::thread t(mytest); //开启一个线程
std::cout<<"hello world\n";
t.join(); //终结线程 }
/*输出
hello world
hello */
  • 1.上面的代码使用了std::thread t,这行代码创建了一个新的线程t,并让它执行mytest函数。当这行代码执行时,mytest函数会在新创建的线程上开始执行。主线程(即创建t的线程)则会继续执行下一行代码。

  • 2.t.join()是一个阻塞调用,意味着主线程会等待,直到线程t(即mytest函数)执行完毕。换句话说,t.join()确保了mytest函数在新线程上完成执行后,主线程才会继续执行后续的代码。如果没有t.join() ,主线程可能在mytest函数完成之前结束,这可能会导致未定义的行为,因为当主线程结束时,所有其他线程都会被强制终止,即使它们还没有完成它们的任务。

利用多线程去计算

多线程可以加快数组元素的计算,例如,我们先创建一个数组,来进行普通的计算,顺便测试一下运行速度。

//一个简单计算的例子
double cf(double v)
{
if (v<=0)
return v;
std::this_thread::sleep_for(std::chrono::milliseconds(1));//让线程停下来1毫秒
return sqrt((v * v+std::sqrt((v-5)*(v+2.5) )/2.0 )/v); //随便的计算
} std::vector<double> vds;
for(int i=0;i<1000;++i)
vds.push_back(rand()); //随机赋值
std::cout<<vds.size()<<'\n'; //大小
double value=0.0;
auto nowc = clock();//现在的时间
for(auto& info :vds)
{
value += cf(info);
}
std::cout<<"value: "<<value<<"spend time is "<<clock()-nowc<<'\n';

输出内容

1000
value: 120539spend time is 16760

接下来,我们使用多线程来计算一下数组元素,我们让主线程计算一半数组元素,开一个线程计算另外一半数组元素。

在多线程中

//这个函数是给数组中从Begin位置到End位置中元素进行计算
template<class T,typename Fun>
double visit(std::thread::id id,T iterBegin,T iterEnd,Fun f)
{
auto mainThreadId = std::this_thread::get_id();//获取主线程id
if(id == mainThreadId)
std::cout<<"This is MAIN Thread \n";
else
std::cout<<"This is WORK Thread \n"; double v=0;
for(auto iter=iterBegin; iter!=iterEnd;++iter)
v+=f(*iter);
return v;
} auto iter = vds.begin() +(vds.size()/2);//数组的后一半
double anotherv = 0.0;
auto iterEnd = vds.end();
nowc = clock();
std::thread s( //这里的mainThreadId
[&anotherv,iter,iterEnd,mainThreadId]()
{
anotherv=visit(mainThreadId,iter,iterEnd,cf);//将当前线程id,计算数组后半的数据
});
auto halfv = visit(mainThreadId,vds.begin(),iter,cf); //计算数组前半的数据
s.join();
std::cout<<"halfv+anotherv: "<<(halfv+anotherv)<<"spend time is "<<clock()-nowc<<'\n';

输出内容

This is MAIN Thread
This is WORK Thread
halfv+anotherv: 120539spend time is 7890

由此可见,用多线程的技术后,计算速度比普通计算快接近一半.我们还可以建立三线程等更多线程来计算

//三线程代码
auto mainThreadId = std::this_thread::get_id();//获取主线程id std::vector<double> vds;
for(int i=0;i<300;++i)
vds.push_back(rand());
std::cout<<vds.size()<<'\n';
double value=0.0; // 让我们测试一下运行速度
auto nowc = clock();//现在的时间
for(auto& info :vds)
{
value += cf(info);
}
std::cout<<"value: "<<value<<" spend time is "<<clock()-nowc<<'\n'; auto begin1 = vds.begin();
auto iter = vds.begin() +(vds.size()/3);
auto iter2 = iter+(vds.size()/3); double anotherv = 0.0;
double anotherv2 = 0.0;
auto iterEnd = vds.end();
nowc = clock();
std::thread s( //这里的mainThreadId
[&anotherv,begin1,iter,mainThreadId]()
{
anotherv=visit(mainThreadId,begin1,iter,cf);//将当前线程id,计算数组后半的数据
});
std::thread s2( //这里的mainThreadId
[&anotherv2,iter,iter2,mainThreadId]()
{
anotherv2=visit(mainThreadId,iter,iter2,cf);//将当前线程id,计算数组后半的数据
}); auto halfv = visit(mainThreadId,iter2,vds.end(),cf); //计算数组前半的数据
s.join();
s2.join();
std::cout<<"halfv+anotherv: "<<(halfv+anotherv+anotherv2)<<" spend time is "<<clock()-nowc<<'\n';
/*
输出
300
value: 36321.9 spend time is 4734
This is MAIN Thread
This is WORK Thread
This is WORK Thread
halfv+anotherv: 36321.9 spend time is 1582
*/

关于线程中的 mainThreadId 还有几点,有以下几点需要澄清:

  • 线程 ID 的唯一性:1std::this_thread::get_id() 1返回调用线程的唯一标识符。因此,主线程和任何新创建的线程都会有不同的 ID。即使您在主线程中和新线程中都调用了 std::this_thread::get_id() 并将其赋值给 mainThreadId,这两个变量也会持有不同的值,因为它们是不同线程的 ID。

  • 捕获列表的作用:在 s 线程的捕获列表中,1mainThreadId 是通过引用捕获的1。这意味着 s 线程中的 mainThreadId 是 main 函数中 mainThreadId 的一个引用。但是,这并不意味着 s 线程中的 mainThreadId 就是主线程的 ID。它只是 main 函数中定义的同一个变量的引用。

  • 变量的生命周期:只要 main 函数还在执行,并且 mainThreadId 还在其作用域内,s 线程就可以通过其捕获的引用访问 mainThreadId。但是,一旦 main 函数结束,mainThreadId 的生命周期也就结束了,此时对 s 线程中捕获的引用的访问将是未定义的。

C++ 多线程笔记1 线程的创建的更多相关文章

  1. Java多线程并发01——线程的创建与终止,你会几种方式

    本文开始将开始介绍 Java 多线程与并发相关的知识,多谢各位一直以来的关注与支持.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程的创建方式 在 Java 中,用户常用的主动创建 ...

  2. AJ学IOS(49)多线程网络之线程的创建NSThreand

    AJ分享,必须精品 一:NSThread的基本使用 1:创建和启动线程 一个NSThread对象就代表一条线程 创建.启动线程 NSThread *thread = [[NSThread alloc] ...

  3. 【Java】多线程相关复习—— 线程的创建、名字、运行情况以及顺序控制(join方法) 【一】

    一.创建线程的三种方式 · 继承Thread类 · 实现Runnable接口 · 实现Callable接口 二. 线程状态 · 线程名字 getName() · 线程活动情况 isAlive() · ...

  4. JAVA学习笔记16——线程的创建和启动

    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码).Java使用线程执行体来代表这段 ...

  5. linux多进/线程编程(7)——多线程1(线程的创建,回收,分离,设置线程属性等)

    参考资料: 1.博客1:https://blog.csdn.net/zhou1021jian/article/details/71531699 2.博客2:https://blog.csdn.net/ ...

  6. Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗

    在上一章,为大家介绍了线程的一些基础知识,线程的创建与终止.本期将为各位带来线程的生命周期与常用方法.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程生命周期 一个线程不是被创建了 ...

  7. iOS-多线程 ,整理集锦,多种线程的创建

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...

  8. java笔记--使用线程池优化多线程编程

    使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库 ...

  9. Linux多线程编程——线程的创建与退出

    POSIX线程标准:该标准定义了创建和操纵线程的一整套API.在类Unix操作系统(Unix.Linux.Mac OS X等)中,都使用Pthreads作为操作系统的线程.Windows操作系统也有其 ...

  10. Java多线程之线程的创建

    好久没有更博客了,最近一直在忙工作的事情.现在终于空下来了,这2天会抓紧时间整理多线程和socket,把JavaSE结束掉. 关于多线程,首先会涉及到哪些东西呢?首先要了解线程,为什么要使用线程,线程 ...

随机推荐

  1. gRPC如何保障数据安全传输

    什么是 gRPC? gRPC 是由 Google 开发的高性能.开源的 RPC(Remote Procedure Call)框架,用于在客户端和服务器之间进行通信.它基于 Protocol Buffe ...

  2. TienChin 渠道管理-工程创建

    因为本文章主要围绕着项目开发进行,所以前言不做开头,直接上内容. 添加字段 我们的渠道表,我看到若依脚手架当中有一个是否删除的标志字段,所以我这里也添加一下: ALTER TABLE `tienchi ...

  3. C#9中使用静态匿名函数

    匿名函数是很早以前在C#编程语言中引入的.尽管匿名功能有很多好处,但它们并不便宜.避免不必要的分配很重要,这就是为什么在C#9中引入静态匿名函数的原因.在C#9中,lambda或匿名方法可以具有静态修 ...

  4. centos7多网口配置同网段IP解决方案

    环境 CentOS Linux release 7.9.2009 (Core) 需求 服务器eth0和eth1配置同网段IP地址.掩码不配网关,同时连接两根网线,对端是两台物理隔离的交换机. 现象 给 ...

  5. Git企业开发控制理论和实操-从入门到深入(六)|多人协作开发

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...

  6. 如果在循环中不改变vector的大小,C++编译器是否会将.size()优化为常数?

      在C++中,可以使用以下代码计算vector<int>中所有元素的和: vector<int> v = {1, 3, 7, 9}; sums = 0; for (int i ...

  7. 【Flink入门修炼】1-2 Mac 搭建 Flink 源码阅读环境

    在后面学习 Flink 相关知识时,会深入源码探究其实现机制.因此,需要现在本地配置好源码阅读环境. 本文搭建环境: Mac M1(Apple Silicon) Java 8 IDEA Flink 官 ...

  8. Python-集合的基本操作(set)

    1. 前言 python中的集合和数学里的类似也是用于存放不重复的元素,它有可变集合(set)和不可变集合(feozenset)两种,集合的所有元素都放在一对大括号"{}"里(列表 ...

  9. 快速上手typescript(进阶篇)

    壹 ❀ 引 我们在快速上手typescript(基础篇)一文中,已经介绍了typescript大部分基础知识,文章结尾也提到这些知识点已足以支撑日常typescript开发,而本文算是对于前文知识点的 ...

  10. 错误发布--如何配置最新的JDK21

    如何配置最新的JDK21 时间:2024/2/3 官网 www.oracle.com 找到对应版本JDK21 可选择语言翻译版本 根据需求选择合适JDK版本.操作系统.位数 三个安装包格式:最简洁的是 ...