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,一经查实,立即删除!

相关文章

pythonfor循环语句例题_python循环语句的使用练习题

1. 使用while循环输出1 2 3 4 5 6 8 9 10 for i in range(10) : if i6 : print( ,end ) continue print(i1,end" ") 2. 求1-100的所有数的和 s0 for i in range(101) : si print(s) 3. 输出 1-100 内的所有奇数 for i in range(100) : if (i1)%21 : print(i1,end ) 4…

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

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

多个定时器相互干扰的问题_相互问题

多个定时器相互干扰的问题HTTPS协议是建立安全连接的公认标准。 理解此协议的工作原理不是问题&#xff0c;并且自2000年以来可以使用相应的RFC文档 。 尽管HTTPS的使用如此广泛&#xff0c;但您仍然可以找到没有不必要的复杂性就无法处理此协议的软件。 不幸的是&#xff0c;…

【WebRTC---进阶篇】(一)服务器基础编程

一个最简单的服务器程序 server.h /*** Server Class ** @author lichao* @date 2019-08-07* @copyleft GPL 2.0*/#ifndef __SERVER_H__ #define __SERVER_H__namespace avdance {class Server {public:Server(); //consrtuct~Server(); //destructpublic:void run();};} //…

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

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

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

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

【WebRTC---进阶篇】(二)libevent实现高性能网络服务器

libevent编译与安装 libevent官网 Linux平台安装编译libevent wget -c addr --no-check-certificate ./configure --prefix=/usr/local/libevent make -j 8 make install #include <event2/listener.h> #include <event2/bufferevent.h> #include <event2/b…

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

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

html按钮冻结,Vue js按钮冻结dom

我想切换一个包含加载动画的按钮按钮&#xff0c;直到该函数完成使用v-if。但是当我按下按钮时&#xff0c;DOM冻结&#xff0c;span元素不变&#xff0c;直到函数调用结束。我如何让DOM不冻结并显示加载图标&#xff1f;非阻塞按钮按下可能是一个解决方案&#xff1f;Vue js按…

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

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

注释嵌套注释_DIY注释

注释嵌套注释从Java 5开始&#xff0c;Java中出现了注释。 我想做一个自己的注释&#xff0c;只是为了看看需要什么。 但是&#xff0c;我发现它们只是接口。 有擦 接口后面没有牙。 必须执行一些代码。 我认为这是橡胶行之有效的方法&#xff0c;我真的找到了解决方法。 首先…

汇编 cmp_汇编复习

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

【WebRTC---进阶篇】(四)mediasoup服务器的布署与使用

Nodejs安装 Nodejs安装 下载mediasoup Demo,并配置 详细GitHub地址 https://github.com/versatica/mediasoup-demo

睡眠是锁定计算机怎么设置密码,电脑休眠锁屏怎么设置

想要保护好自己的隐私&#xff0c;就要懂得电脑休眠锁屏怎么设置哦&#xff01;什么&#xff1f;你不会设置&#xff1f;不怕&#xff0c;小编这就来为您支招&#xff01;请看下文内容&#xff01;电脑休眠锁屏怎么设置用户账户面板1、首先您需要创建用户密码&#xff0c;如果您…

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…

java工程引入scala_引入ReactiveInflux:用于Scala和Java的无阻塞InfluxDB驱动程序,支持Apache Spark...

java工程引入scala我很高兴宣布Pygmalios开发的ReactiveInflux的第一个发行版。 InfluxDB错过了Scala和Java的非阻塞驱动程序。 不变性&#xff0c;可测试性和可扩展性是ReactiveInflux的关键功能。 加上对Apache Spark的支持&#xff0c;它是首选武器。 https://github.com/p…

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

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