C++ 11 深度学习(十五)多线程

线程创建

方式一:调用函数

#include<thread>void CreateThread()
{int a=100;cout<<"This is Thread: "<<a<<endl;
}int main()
{thread   Threadone(CreateThread);//join是一种阻塞的方式,需要子线程处理完毕之后,才切换回主线程继续执行Threadone.join();//or  detach是一种分离处理,归系统来管理Threadone.detach();}

方式二:使用类对象,需要operator( )( )才能成为可调用对象

#include<thread>
#include <iostream>
#include<mutex>
using namespace std;class TA
{
public:void operator()()//不能带参数{cout << "Thread to start" << endl;}
};int main()
{mutex tex;TA ta;thread  Mythread(ta);Mythread.join();cout << "主线程执行" << endl;return 0;
}

方法三:类成员函数作为线程入口

#include <iostream>
#include <thread>
using namespace std;class A
{
public:void prin() {};
};int main() {A aa;thread myobj(&A::prin, aa);if (myobj.joinable()) {myobj.detach();}return 0;
}

使用类成员函数作为线程入口封装Thread库存

#pragma once#include<string>
#include<iostream>
#include<thread>class BaseThread
{
public:void Start();void Wait();void Stop();bool is_exit();private:virtual void Run() = 0;private:std::thread thread_;bool is_exit_ = false;};class TestXThread : public BaseThread
{
public:void Run()override;
};
#include "BaseThread.h"void BaseThread::Start()
{thread_ = std::thread(&BaseThread::Run, this);
}void BaseThread::Wait()
{if (thread_.joinable()){thread_.join();}
}void BaseThread::Stop()
{is_exit_ = true;Wait();
}bool BaseThread::is_exit()
{return is_exit_;
}void TestXThread::Run()
{std::cout << "TestXThead Main begin" << std::endl;while (!is_exit()){std::cout << "." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(1));}std::cout << "TestXThead Main end" << std::endl;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include"BaseThread.h"
using namespace  std;int main()
{TestXThread testth;testth.Start();std::this_thread::sleep_for(std::chrono::seconds(1));testth.Stop();testth.Wait();system("pause");return 0;
}

注意

1.joinable()可以用来查看是否处于join或者detach状态,如果是返回true,否则返回false。

全局函数作为线程入口分析参数传递内存操作

1.线程中所有传递的参数是基础类型,所有参数都会被复制一份

2.线程中传递的是对象对象会被复制拷贝,调用了拷贝构造函数。

detach大坑

#include <iostream>
#include <memory>
#include <thread>
using namespace std;
void myprint(const int &i, char *pmybuf)
{cout << i << endl; cout << pmybuf << endl;return;
}int main() {int mavar = 1;int &mvary = mavar;char mybuf[] = "hello";thread myobj(myprint, mavar, mybuf);if (myobj.joinable()) {myobj.detach();}return 0;
}

以上代码存在的问题:

1.mybuf在主线程结束后会被销毁,导致线程中使用出问题。解决问题:

#include <iostream>
#include <thread>
using namespace std;
void myprint(const int &i, const string &pmybuf)
{cout << i << endl; cout << pmybuf.c_str() << endl;return;
}int main() {int mavar = 1;int &mvary = mavar;char mybuf[] = "hello";//string(mybuf)生成临时对象thread myobj(myprint, mavar, string(mybuf));if (myobj.joinable()) {myobj.detach();}return 0;
}

 获取线程ID

std::this_thread::get_id()

总结:

1.在使用thread::detach(类对象)或者(基础类型的时候)只要不对其进行(指针)和(引用)等操作是可以保证线程在主线程结束时,也在后台正常运行的。

2.通过构建(临时l类对象)的方法,其构造是在(主线程)中进行构造的,消除了在子线程构造的情况。

线程函数传递指针和引用

1.在传入指针或者引用的情况下,防止线程访问的空间被提前释放,解决方法:

(一) 传递堆内存中

(二) 使用静态的

(三)参数放到类成员当中

2.在线程中真正想要修改传入参数的,需要使用以下函数

std::ref(要传入的参数)
thread myobj(myprint, std::ref(mavar), string(mybuf));

  3.如果传递参数为智能指针,可以使用以下方式,需要使用join,detach会出现内存问题

std::move(要传入的智能指针);
	unique_ptr<int>ptr(new int(100));thread myobj(myprint, std::move(ptr), string(mybuf));

创建和等待多个线程

#include <iostream>
#include <thread>
#include <vector>using namespace std;//线程入口函数
void myprint(int inum)
{cout << "myprint thread start , thread id is :"<< inum << endl;return;
}int main() {//创建和等待多个线程vector<thread>mythread;//创建十个线程for (int i = 0; i < 10; i++){mythread.push_back(thread(myprint, i));//创建并开始执行线程}for (auto ider = mythread.begin(); ider != mythread.end(); ider++){ider->join();}cout << "main thread" << endl;return 0;
}

共享数据的保护案例

1.以上程序打印的时候会出现以下问题,即打印不一致

2.创建两个线程,一个队列,其中一个线程负责向队列写入,一个线程负责从队列中取出,以此来保证读写平衡;该设计存在一个问题(在读写操作会产生崩溃问题)

#include <iostream>
#include <thread>
#include <vector>
#include <list>using namespace std;class A
{
public://把收到的消息插入到队列void inmsgRecvQueue(){for (int i = 0; i < 100000; ++i){cout << "msgRecvQueue插入一个元素: " << i << endl;msgRecvQueue.push_back(i);}}void outmsgRecvQueue(){for (int i = 0; i < 100000; ++i){if (!msgRecvQueue.empty()){cout << "msgRecvQueue取出一个元素: " << msgRecvQueue.front() << endl;msgRecvQueue.pop_front();}else{cout << "msgRecvQueue队列为空!!!!! "  << endl;}}}private:list<int>msgRecvQueue;
};int main() {A aa;//创建和等待多个线程thread objectB(&A::outmsgRecvQueue,&aa);thread objectA(&A::inmsgRecvQueue,&aa);objectA.join();objectB.join();cout << "main thread" << endl;return 0;
}

互斥量

互斥量的作用是对于上述情况,对多线程读写共享数据进行保护。

1.使用mutex进行互斥加锁保护

#include <iostream>
#include <thread>
#include <mutex>
#include <list>using namespace std;class A
{
public://把收到的消息插入到队列void inmsgRecvQueue(){for (int i = 0; i < 100000; ++i){cout << "msgRecvQueue插入一个元素: " << i << endl;//保护位置加锁mymutex.lock();msgRecvQueue.push_back(i);mymutex.unlock();}}bool outMsgLulQueue(int &value){//加锁操作mymutex.lock();if (!msgRecvQueue.empty()){value = msgRecvQueue.front();msgRecvQueue.pop_front();mymutex.unlock();return true;}mymutex.unlock();return false;}void outmsgRecvQueue(){int nums = 0;for (int i = 0; i < 100000; ++i){if (outMsgLulQueue(nums)){cout << "Queue取出的元素为" << nums << endl;}else{cout << "Queue无元素" << nums << endl;}}}private:list<int>msgRecvQueue;mutex mymutex;
};int main() {A aa;//创建和等待多个线程thread objectB(&A::outmsgRecvQueue,&aa);thread objectA(&A::inmsgRecvQueue,&aa);objectA.join();objectB.join();cout << "main thread" << endl;return 0;
}

2.lock_guard<mutex>sbguard(mutex对象名),在使用此模板时不能再使用lock和unlock,其原理为lock_guard在构造函数中执行了参数的lock,在析构的时候执行了参数的unlock。

#include <iostream>
#include <thread>
#include <mutex>
#include <list>using namespace std;class A
{
public://把收到的消息插入到队列void inmsgRecvQueue(){for (int i = 0; i < 100000; ++i){cout << "msgRecvQueue插入一个元素: " << i << endl;{lock_guard<mutex>sbguard(mymutex);//保护位置加锁/*mymutex.lock();*/msgRecvQueue.push_back(i);/*mymutex.unlock();*/}}return;}bool outMsgLulQueue(int &value){//自旋锁lock_guard<mutex>sbguard(mymutex);/*mymutex.lock();*/if (!msgRecvQueue.empty()){value = msgRecvQueue.front();msgRecvQueue.pop_front();/*mymutex.unlock();*/return true;}/*mymutex.unlock();*/return false;}void outmsgRecvQueue(){int nums = 0;for (int i = 0; i < 100000; ++i){if (outMsgLulQueue(nums)){cout << "Queue取出的元素为" << nums << endl;}else{cout << "Queue无元素" << nums << endl;}}}private:list<int>msgRecvQueue;mutex mymutex;
};int main() {A aa;//创建和等待多个线程thread objectB(&A::outmsgRecvQueue,&aa);thread objectA(&A::inmsgRecvQueue,&aa);objectA.join();objectB.join();cout << "main thread" << endl;return 0;
}

3.死锁(至少有两个互斥量才会产生)

存在两个锁a,b的情况下,两个线程A,B。当线程A的a锁定以后,在尝试b锁的时候,由于上下文切换。切换到B线程执行,B线程执行b锁成功,再去尝试a锁的时候会出现a不能加锁,同样线程A也产生同样的情况(即产生死锁)。

解决死锁的方案:

1.加锁顺序保持一致;

2.使用std::lock(参数一,参数二,--),该函数用来同时锁定多个互斥量,只有同时都锁定了才成功,否则会立即把已经锁住的释放锁。

3.std::adopt_lock是一个结构体,标记着在lock_guard中不再对当前参数执行lock操作,使用此方法的前提是互斥量mutex已经执行了lock

lock_guard<mutex>sbguard(mymutex,std::adopt_lock);

4.std::try_to_lock,会尝试使用mutex的lock去锁定mutex,如果没有锁定成功也会立即返回,不会阻塞,使用此方法之前不能调用lock

unique_lock<mutex>sbguard(mymutex, std::try_to_lock);

5.std::defer_lock ,初始化对mutex不进行lock操作,使用该方法的前提是互斥量mutex不能调用lock

unique_lock<mutex>sbguard(mymutex, std::defer_lock);

6. unique_lock<mutex>的成员函数

		unique_lock<mutex>unitex(mymutex, std::defer_lock);//加锁unitex.lock();//解锁unitex.unlock();//尝试加锁,成功返回true,失败返回false,失败时不阻塞unitex.try_lock();//返回它所管理的mutex对象,并释放所有权,也就是说unique_lock和mutex不再关联unitex.release();//转移所有权,通过moveunique_lock<mutex>unitex1(std::move(unitex));//判断是否拿锁成功sbguard.owns_lock();

补充部分: 

	//线程延迟20000毫秒std::chrono::milliseconds dura(20000);std::this_thread::sleep_for(dura);

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

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

相关文章

计算机的好处和坏处的英语作文,电脑的利弊英语作文

电脑的利弊英语作文在学习、工作或生活中&#xff0c;大家都写过作文吧&#xff0c;通过作文可以把我们那些零零散散的思想&#xff0c;聚集在一块。那么你有了解过作文吗&#xff1f;下面是小编为大家整理的电脑的利弊英语作文&#xff0c;希望能够帮助到大家。Computer is in…

servlet容器_SpringBoot是否内置了Servlet容器?

SpringBoot是否内置了Servlet容器&#xff1f;SpringBoot内置了Servlet容器&#xff0c;这样项目的发布、部署就不需要额外的Servlet容器&#xff0c;直接启动jar包即可。SpringBoot官方文档上有一个小章节内置servlet容器支持用于说明内置Servlet的相关问题。在SpringBoot源码…

计算机专业开学要带电脑吗,大学上课要带电脑吗

大学刚开学&#xff0c;上课的时候学生们要不要带电脑呢&#xff0c;想必这个问题一直对还没进入大学的准大学生来说很困扰&#xff0c;下面是小编整理的详细内容&#xff0c;一起来看看吧&#xff01;大学上课要带电脑吗大学上课能否带电脑需要看老师的要求。大学课程书本知识…

突然讨厌做前端,讨厌代码_不要讨厌HATEOAS

突然讨厌做前端,讨厌代码或我如何学会不再担心和爱HATEOAS REST已成为实现Web服务的事实上的解决方案&#xff0c;至少已成为一种流行的解决方案。 这是可以理解的&#xff0c;因为REST在使用HTTP规范时提供了一定程度的自我文档。 它经久耐用&#xff0c;可扩展&#xff0c;并…

【WebRTC---进阶篇】(三)各流媒体服务器的比较

多人音视频架构 Mesh方案 多对多大多进行P2P,在国内P2P直连穿越会出现很大问题。 MCU方案 客户端连接后,对应每个终端都有一个模块进项上传。再将音视频进行拆分解码。进行混屏,压缩编码分别推动给每个终端。 SFU方案 sfu不进行编解码,只是进行转发。只对订阅的终端进行…

汇编 cmp_汇编复习

第一章计算机组成五部分&#xff1a;&#xff08;运算器、控制器&#xff09;、存储器、输入/输出设备↑↑ CPU ↑↑ ↑内存↑三条总线&#xff1a;控制总线、地址总线、数据总线不同进制及BCD码的转换特殊ascll ‘0’~‘9’—— 30H ~ 39H‘A’~‘F’—— 41H ~ 46H回车 —— …

junit5和junit4_JUnit 5 –设置

junit5和junit42015年11月&#xff0c; JUnit Lambda团队展示了他们的原型 。 此后&#xff0c;该项目更名为JUnit 5&#xff0c;并于2016年2月发布了Alpha版本。我们将在一系列简短文章中进行探讨&#xff1a; 建立 基本 建筑 条件 注射 … 本节讨论JUnit 5的设置&…

markdown 生成目录_github上如何为markdown文件生成目录

写在前面熟悉markdown都知道可以使用[TOC]自动生成markdown文件的标题目录&#xff0c;比如在typora&#xff0c;vscode(需要插件)等本地编辑器中&#xff0c;或者在CSDN等网页编辑器中&#xff0c;但是github却不支持[TOC]标签&#xff0c;至于为什么不支持感兴趣的可以深入搜…

【WebRTC---进阶篇】(五)mediasoup的信令系统

mediasoup demo分析 app 客户端部分 broadcasters 推拉流部分 server 服务端部分 config.js 相当于一个配置文件&#xff0c;获取一些基本配置信息。获取的信息来交给server.js。 server.js 先从config.js获取信息&#xff0c;然后启动HTTPS webSocket服务等&#xff0c;…

axure html尺寸,axure怎么确定尺寸

回答&#xff1a;您好如做的是室内设计的话&#xff0c;那么来说可能会些参数提供给您的(例如长宽高)如果没有参数的话&#xff0c;只要把比例做好就可以了。只要比例做好了&#xff0c;东西看起来就自然像。至于教程的话&#xff0c;一般录制教程前都会有做好准备的&#xff0…

exe打包工具哪个最好_为你的 Python 程序写个启动工具箱

到目前为止&#xff0c;公众号已经介绍了不少图形界面的软件&#xff0c;比如猜数游戏、PDF阅读器、贪吃蛇游戏、天气查询软件、PDF 阅读器等。为了方便他人使用&#xff0c;我们常把图形界面打包成 exe 文件。但是如果我们只是为了自己使用方便的话&#xff0c;我们有必要把程…

【WebRTC---进阶篇】(六)SELECT网络模型

select函数原型 int WSAAPI select(_In_ int nfds,_Inout_opt_ fd_set FAR * readfds,_Inout_opt_ fd_set FAR * writefds,_Inout_opt_ fd_set FAR * exceptfds,_In_opt_ const struct timeval FAR * timeout); 函数功能:监视多个文件描述符的状态变化,在IO中负责IO的第一步…

计算机管理没有打印机列队,在Windows清除打印队列如果打印机被卡住,也没有打印输出...

我相信自己已经勾起回忆一拉似曾相识 &#xff0c;右侧的主题&#xff1f; 我们每个人&#xff0c;在一段时间或其他&#xff0c;都在打印过程中面临的问题&#xff0c;特别是给打印命令&#xff0c;并打印输出不休后等待。 无论是在家里还是办公室里&#xff0c;那就是我们所有…

gatling 使用_使用Gatling + Gradle + Jenkins Pipeline为您的JAX-RS(和JavaEE)应用程序进行连续压力测试...

gatling 使用在这篇文章中&#xff0c;我将解释如何使用Gatling项目为您的JAX-RS Java EE端点编写压力测试&#xff0c;以及如何将它们与Gradle和Jenkins Pipeline集成&#xff0c;因此&#xff0c;除了进行简单的压力测试外&#xff0c;您还可以使用以下方法&#xff1a; 连续…

java comparator_【面试题】Java必考面试题全集(15)

Java基础面试题(15)1&#xff1a;Comparator 与Comparable 有什么不同&#xff1f;2&#xff1a;Object中有哪些方法&#xff1f;3&#xff1a;说下jdk8中的一些新特性4&#xff1a;在64 位 JVM 中&#xff0c;int 的长度是多数&#xff1f;5&#xff1a;java每改一点都需要重新…

px是什么意思计算机二级,px是什么意思?照片中的px是什么的缩写?

px是什么意思?px(Pixel&#xff0c;像素)是可以在数字显示设备上显示和表示的数字图像或图形的最小单位。像素是数字图形中的基本逻辑单元。将像素组合在一起以在计算机显示器上形成完整的图像&#xff0c;视频&#xff0c;文本或任何可见的东西。像素也称为图像元素。若把影像…

java 交替_Java 8:使用交替接口公开的类型安全地图生成器

java 交替动态展示您的课程 当我还是Java新手时&#xff0c;我记得当时以为应该有一种方法可以删除或隐藏我不想公开的类中的方法。 就像用private方法或类似方法覆盖public方法一样&#xff08;哪种情况是不可能的&#xff0c;也不应该是不可能的&#xff09;。 显然&#xff…

ieee期刊_论文绘图神器来了:一行代码绘制不同期刊格式图表,哈佛博士后开源...

贾浩楠 发自 凹非寺量子位 报道 | 公众号 QbitAI「一篇论文投多个期刊&#xff0c;每个期刊对图表格式要求不一&#xff0c;同一组数据要用多种工具分别绘图。」不光是你&#xff0c;哈佛大学天文研究所的博士后&#xff0c;也不堪忍受论文重复绘图之苦。他的解决办法是&#x…

微课与计算机技术的论文,微课在高校计算机教学的运用论文

微课在高校计算机教学的运用论文摘要&#xff1a;现代信息社会不断发展进步&#xff0c;高校计算机教学也面临着复杂的形势&#xff0c;为全面提高计算机教学质量&#xff0c;提升学生的专业素质及综合能力&#xff0c;应当微课加以科学化应用。本文基于微课的内涵及应用意义出…

spring 启动加载数据_12个很棒的Spring数据教程来启动您的数据项目

spring 启动加载数据Spring Data的任务是为数据访问提供一个熟悉且一致的&#xff0c;基于Spring的编程模型&#xff0c;同时仍保留基础数据存储的特​​殊特征。 它使使用数据访问技术&#xff0c;关系和非关系数据库&#xff0c;map-reduce框架以及基于云的数据服务变得容易…