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. vue全局事件总线和消息订阅详细讲解

    全局事件总线 在写组件的时候,我们都知道父传递子 也知道子传递给父 但是组件间嵌套复杂的时候我们应该怎么通信呢? 有的小伙伴会说适用vuex,的确是可以解决问题的 下面我们说一下全局事件总线 一种组件 ...

  2. OpenIM (Open-Source Instant Messaging) Mac Deployment Guide

    This guide provides step-by-step instructions for deploying OpenIM on a Mac, including both source c ...

  3. 设计模式学习-使用go实现备忘录模式

    备忘录模式 定义 优点 缺点 适用范围 代码实现 参考 备忘录模式 定义 备忘录( Memento ):在不破坏封装性的前提下,获取一个对象的内部状态,并在该对象之处保存该状态.这样以后就可将该对象恢 ...

  4. 【踩坑记录】SpringBoot跨域配置不生效

    问题复现: 明明在拦截器里配置了跨域,就是不生效,使用PostMan等后端调试工具调试,均正常,Response中有Access-Control-Allow-Origin: *,这个Header,但是 ...

  5. SqlSugar子查询

    1.基础教程 1.1 API目录 *****只查一列***** //First: SqlFunc.Subqueryable<School>().Where(s => s.Id ==  ...

  6. 4.4 EAT Hook 挂钩技术

    EAT(Export Address Table)用于修改动态链接库(DLL)中导出函数的调用.与IAT Hook不同,EAT Hook是在DLL自身中进行钩子操作,而不是修改应用程序的导入表.它的原 ...

  7. LeetCode刷题日记 2020/03/26

    题干 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc ...

  8. 小米WIFI 7路由器BE6500 Pro开箱

    上次发帖与坛子里的网友们聊了小米的这款路由,正好今天拿到货了,所以来个开箱图,让其他彦祖们也见识见识小米家的路由产品. 以前买过小米家的路由器,但是当时就是买来尝鲜,这次咋的也是对WIFI 7的尝鲜吧 ...

  9. 【算法】【回溯】两道经典排列问题OJ详解【力扣46 力扣47】【超详细的回溯算法教程】让我们牢牢把握回溯的精髓

    [算法][回溯]两道经典排列问题OJ详解[力扣46 力扣47][超详细的回溯算法教程]让我们牢牢把握回溯的精髓 作者: @小小Programmer 这是我的主页:@小小Programmer 在食用这篇 ...

  10. CF763E Timofey and our friends animals题解

    题目链接:CF 或者 洛谷 简单来说就是求 \([l,r]\) 这些点都存在的情况下,连通块的数量,看到七秒时限,而且每个点相连的边数很少,可以想到离线下来使用莫队类的算法解决 连通块问题,一般可以考 ...