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. Gin 框架之Cookie与Session

    目录 一.Cookie和Session的由来 二.Cookie简介 1. 什么是Cookie 2. Cookie规范 3. 安全性 4. Cookie 关键配置 三.Session简介 1. 什么是S ...

  2. 将input 中的小写字母转化为大写字母

    小写转换为大写,使用toLocaleUpperCase() options.element.find(".CarNumber").textbox({ label: '车牌号:', ...

  3. 从零开始配置 vim(6)——缩写

    关于vim能快速编辑文本的能力,我们见识到了 operator + motion ,见识到了. 范式和宏.甚至可以使用命令来加快文本编辑.在后面我们又介绍了快捷键绑定来快速执行我们想要的操作.今天我们 ...

  4. Python使用Paramiko实现SSH管理

    paramiko 是一个用于在Python中实现SSHv2协议的库,它支持对远程服务器进行加密的通信.目前该模块支持所有平台架构且自身遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接,你 ...

  5. c#树结构转npoi复杂表头

    Vue 前端框架框架中采用树结构打印表头,为了前后端适配NPOI导出. 这里重点做树结构转换 NPOI 复杂表头的结构数据( 跨行.跨列),其它具体导出功能请参考  https://www.cnblo ...

  6. .NetCore 三种生命周期注入方式

    .NetCore彻底诠释了"万物皆可注入"这句话的含义,在.NetCore中到处可见注入的使用.因此core中也提供了三种注入方式的使用,分别是: AddTransient:每次请 ...

  7. 苹果新一代“超级芯片”曝光:M3 Ultra最高可达32核CPU

    近日,据外媒消息,苹果计划在2024年推出新一代"超级芯片"M3 Ultra. 据悉,M3 Ultra将大幅增加CPU核心数量,同时GPU核心数量也将适度增加. 具体来说,M3 U ...

  8. 试用Proxmox VE 8.0搭建云桌面系统

    6月22日发布了其服务器虚拟化管理平台 Proxmox 虚拟环境的稳定版 0.12.这个主要版本基于最新的Debian 7("书虫"),并为Proxmox VE 4.8或旧版本的用 ...

  9. Java并发(八)----使用线程避免cpu占用100%

    1.sleep 实现 在没有利用 cpu 来计算时,不要让 while(true) 空转浪费 cpu,这时可以使用 yield 或 sleep 来让出 cpu 的使用权给其他程序 while(true ...

  10. 轻量级按键动作识别模块(C语言)

    1.前言 继嵌入式(单片机)裸机 C 语言开发 + 按键扫描(模块分层/非阻塞式)文章后,原来的按键识别基本能满足大部分需求,但是对于双击和多击等多样化的功能需求并不能满足,因此对整个按键动作识别模块 ...