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. Qt连接MySQL的问题解决方法

    Qt5在连接MySQL数据库时会出现一些问题,本文介绍两种最常见的问题,以及其相对简单的解决办法. Qt5数据库支持列表里没有MySQL 输入以下代码查看支持的数据库类型 //打印支持的数据库类型 q ...

  2. golang uuid库介绍

    简介: 在现代软件开发中,全球唯一标识符(UUID)在许多场景中发挥着重要的作用.UUID是一种128位的唯一标识符,它能够保证在全球范围内不重复.在Go语言中,我们可以使用第三方库github.co ...

  3. Protobuf示例:Golang and Python

    之前的文章中已经展示过如何在C++中使用protobuf,本文将简单示范protobuf在Golang和Python中的使用. Talk is cheap. Show you my code. 首先是 ...

  4. GIT专业术语教程-转载

    目录 一.版本控制概要 1.1.什么是版本控制 1.2.常用术语 1.3.常见的版本控制器 1.4.版本控制分类 1.4.1.本地版本控制 1.4.2.集中版本控制 1.4.3.分布式版本控制 1.5 ...

  5. C/C++ x64 Inline Hook 代码封装

    Hook 技术常被叫做挂钩技术,挂钩技术其实早在DOS时代就已经存在了,该技术是Windows系统用于替代DOS中断机制的具体实现,钩子的含义就是在程序还没有调用系统函数之前,钩子捕获调用消息并获得控 ...

  6. ElasticSearch-索引库、文档操作

    1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 2.elasticsearch和lucen ...

  7. 关于React-Router6 (React 路由)

    一.概要 (1)每个单页应用其实是一系列的 JS 文件,当用户请求网站时,网站返回一整个(或一系列)的 js 文件和 HTML,而当用户在某个页面内点击时,你需要告诉浏览器怎么加载另一个页面地址.单页 ...

  8. Docker从认识到实践再到底层原理(六-1)|Docker容器基本介绍+命令详解

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

  9. PHP中目录操作函数

      PHP中目录操作函数 1.是否是目录 is_dir 判断给定文件名是否是一个目录 $path = dirname(__FILE___); echo is_dir($path) ? '目录' : ' ...

  10. Markdown Rules 详解

    使用VSCode编写Markdown文件时,建议安装插件markdownlint,它可以帮助自己更加规范的写文章. 下面是所有的markdown语法错误信息以便纠错. Rules文档 Markdown ...