C++11多线程编程 一:多线程概述

news2024/12/22 18:34:03

1.1 第一个线程代码示例-线程创建示例

        多线程编程当中,每一个程序运行都至少会有一个线程,一般的main函数都作为主线程的入口,这里面是一个进程包含一个主线程,一个进程里面包含多个子线程,所以一般在主线程当中(也就是main函数中)再去启动一个子线程。
 
        需要包含头文件:#include <thread>
        用到的类:thread th(ThreadMain); 线程创建并启动
        阻塞等待函数:th.join();当子线程退出之后才解除阻塞
        如果不阻塞等待子线程退出的话,也就是把th.join();去掉,那么主线程运行完,就把th对象给销毁了,而这时子线程还在运行,这时就会弹窗报错。

 
        问题线程的话,是创建好,运行完回调函数就自动退出么?而主函数会把在内部创建的线程对象同时给销毁,也就是说应该先退出子线程再销毁线程对象。

#include <thread>
#include <iostream>
//Linux 中要链接动态库 -lpthread
using namespace std;
 
void ThreadMain()
{
    cout << "begin sub thread main " << this_thread::get_id() << endl; // get_id()获取当前线程ID
    for (int i = 0; i < 10; i++)
    {
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
    cout << "end sub thread main " << this_thread::get_id() << endl;
}
int main(int argc, char* argv[])
{
    cout << "main thread ID " << this_thread::get_id() << endl;
    //线程创建并启动
    thread th(ThreadMain);
    cout << "begin wait sub thread  " << endl;
    //阻塞等待子线程退出
    th.join();
    cout << "end wait sub thread  " << endl;
    return 0;
}
#编译
g++ -o main main3.c -lpthread

 结果:

 

        线程的退出:我们这里创建了一个子线程,假如我们让他运行10s后再退出,这里就涉及到一个问题,假如里面是一个死循环,那么就会把单个CPU的资源耗尽,而有些任务处理的时候并不是计算任务,而只是在等待某一个结果,那么这个时候就可以在子线程中选择释放CPU资源,这里使用其中的一种方式,就是sleep,sleep就是当前线程释放CPU多长时间。

        上面第8行和第21行,这两个打印输出可能是同时执行的,因为是多核并发,因此最后反应在屏幕上可能导致两行字叠在一块儿了。


1.2 thread对象生命周期和线程等待和分离

 

         这里面导致错误的原因有多个,第一个首先是主线程退出了,那么我们先要保证主线程不要退出

 但是结果还是跟上面一样。

我们希望主线程和子线程同时运行,然后我们又不想维护th这个对象(当然还有一种方式就是维护这个对象)那怎么办?

#include <thread>
#include <iostream>
//Linux -lpthread
using namespace std;
bool is_exit = false;//通过这个标志位通知子线程退出
 
void ThreadMain()
{
    cout << "begin sub thread main " << this_thread::get_id() << endl;
    for (int i = 0; i < 10; i++)
    {
        if (is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
    cout << "end sub thread main " << this_thread::get_id() << endl;
}
int main()
{
    {
        //thread th(ThreadMain);
        //th.detach();
        //主子线程分离,子线程就变成了在后台运行的线程,与主线程无关
        //坑:主线程退出后 子线程不一定退出,那造成一个什么现象,主线程退出之后,主线程的全局空间,
        //栈空间等全部都释放掉了,一旦子线程访问了这些空间,那么程序就会崩溃掉,在Windows中,写完程序
        //关闭的时候弹出一个错误窗口,那么多半是你还在运行的线程访问了静态成员变量或者全局变量,因为
        //变量都被销毁掉了,你还在访问它,那么就会出现错误。
    }
    {
        thread th(ThreadMain);
        this_thread::sleep_for(chrono::seconds(1));//1000ms
        is_exit = true; //通知子线程退出
        cout << "主线程阻塞,等待子线程退出" << endl;
        th.join(); //主线程阻塞,等待子线程退出
        cout << "子线程已经退出!" << endl;
    }
    //getchar();
    return 0;
}

 

        那么如何避免这样的情况呢?如果你用detach()函数分离了一个子线程,那么最后程序却崩溃了,那你的子线程就不要访问外部的变量了,就只访问线程函数内部的变量就行了,或者就是在主线程退出的时候通知一下我们,然后我们去退出,但是这种方式在实际问题中问题也比较多,所以大部分情况下不做detach了,而你又必须维系th这样的一个对象,不然你把对象删了,而子线程还在跑就会报错,那么我们就在整个程序析构的时候调用join函数就行了。


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

#include <thread>
#include <iostream>
#include <string>
//Linux -lpthread
using namespace std;

class Para{
public:
    Para() { cout << "Create Para" << endl; }
    Para(const Para& p)
    {
        cout << "Copy Para" << endl;
        this->name = p.name;
    }
    ~Para() { cout << "Drop Para" << endl; }
    string name;
};
 
void ThreadMain(int p1, float p2, string str, Para p4){
    //延时100ms,确保f1被释放掉,因为此时主线程已经走到th.join();了
    //f1传过来后是拷贝,因此外部f1的销毁这里不受影响
    this_thread::sleep_for(100ms);
    cout << "ThreadMain " << p1 << " " << p2 << " " << str << " " << p4.name << endl;
}
 
int main(int argc, char* argv[]){
    thread th;
    //在栈空间中,一对大括号之后就会释放
    {
        //当这个f1释放之后,当调用thread创建线程这一行代码的时候,后面的参数都做了一份拷贝
        float f1 = 12.1f;
        Para p;
        p.name = "test Para class";
        //所有的参数做复制
        th = thread(ThreadMain, 101, f1, "test string para", p);
    }
    th.join();
    return 0;
}
#编译
g++ -o main main3.c -lpthread

这是Linux下的输出

 

这是Windows下VSstudio的输出,有点搞不明白两次结果为什么不一样,对Windows的结果解释:大括号中间创建一次,传递到thread函数拷贝构造一次,再次调用回调函数时候再次拷贝构造一次。所以一共创建了三次。所以使用值传递的方式会有很大的拷贝开销,应该多多考虑使用引用传递和指针传递。

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

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

相关文章

【离线数仓-8-数据仓库开发DWD层设计要点-交易域相关事实表】

离线数仓-8-数据仓库开发DWD层设计要点-交易域相关事实表离线数仓-8-数据仓库开发DWD层设计要点-交易域相关事实表一、DWD层设计要点二、交易域相关事实表1.交易域加购事务事实表1.加购事务事实表 前期梳理2.加购事务事实表 DDL表设计分析3.加购事务事实表 加载数据分析1.首日全…

Nginx 和 Tomcat 实现负载均衡

Nginx 和 tomcat 实现负载均衡 &#x1f3c6;荣誉认证&#xff1a;51CTO博客专家博主、TOP红人、明日之星&#xff1b;阿里云开发者社区专家博主、技术博主、星级博主。 &#x1f4bb;微信公众号&#xff1a;微笑的段嘉许 &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &am…

【模拟集成电路】电荷泵(CP)设计

电荷泵&#xff08;CP&#xff09;设计前言一、电荷泵&#xff08;CP&#xff09;原理&#xff08;1&#xff09;电流失配问题&#xff08;2&#xff09;开关管的时钟馈通问题&#xff08;3&#xff09;电荷注入问题二、电荷泵&#xff08;CP&#xff09;电路三、电荷泵性能测试…

springboot+jersey+tomcat实现跨域方式上传文件到服务器

前言 在服务器上&#xff0c;当我们启动了tomcat&#xff0c;就可以以 http://ip地址:8080/文件路径/文件名 的方式&#xff0c;进行访问到我们服务器上处于tomcat的webapps文件夹下的文件 于是为了可以往上面加文件&#xff0c;我们有两种方式&#xff0c;一种就是直接复制文…

ABAP 辨析CO|CN|CA|NA|CS|NS|CP|NP

1、文档说明 本篇文档将通过举例&#xff0c;解析字符的比较运算符之间的用法和区别&#xff0c;涉及到的操作符&#xff1a;CO|CN|CA|NA|CS|NS|CP|NP 2、用法和区别 用法总览 以下举例&#xff0c;几乎都使用一个字符变量和一个硬编码字符进行对比的方式&#xff0c;忽略尾…

OAK相机如何将yoloV7模型转换成blob格式?

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

centos7安装

centos7安装制作U盘启动盘下载镜像下载 UltralISO制作启动盘使用U盘安装系统修改模式为 UEFI调整BOOT option保存重启进入安装界面安装图形界面安装搜狗输入法制作U盘启动盘 下载镜像 去官网下载镜像&#xff0c;找到 mirrors链接&#xff08;速度快&#xff09; 选择一个中…

OpenAI是什么

OpenAI是一家非营利性人工智能研究公司&#xff0c;致力于研究人工智能和其他机器学习技术。OpenAI 会和谷歌、苹果、IBM 等知名公司创办的其它一系列项目一道探索先进计算机技术&#xff0c;解决面部识别或语言翻译等问题。 OpenAI 是由马斯克、奥特曼等人 2015 年联合创办的人…

奔四的路上,依旧倔强的相信未来

本文首发于2022年12月31日 原标题: 奔四的路上,依旧倔强的相信未来!–我的2022年终总结 读大学那几年,一直保持着写日记和做计划的习惯,还记得大学毕业刚开始打工的时候,我的床头的墙上一定会画一张表,写上一个月的计划和一周的计划 计划也会有完不成的时候,但加深了…

【Hello Linux】初识冯诺伊曼体系

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍冯诺伊曼体系 冯诺伊曼体系 冯诺伊曼体系结构的合理性 我们在Linux的第一篇博客中讲解了第一台计算机的发明是为了解决导弹的…

实例7:树莓派呼吸灯

实例7&#xff1a;树莓派呼吸灯 实验目的 通过背景知识学习&#xff0c;了解digital与analog的区别。通过GPIO对外部LED灯进行呼吸控制&#xff0c;熟悉PWM技术。 实验要求 通过python编程&#xff0c;用GPIO控制LED灯&#xff0c;使之亮度逐渐增大&#xff0c;随后减小&am…

交换字符使得字符串相同[贪心]

贪心前言一、交换字符使得字符串相同二、贪心1、分析问题的思路过程2、go总结参考资料前言 贪心算法&#xff0c;必须先看清楚有哪些选择&#xff0c;才能在这些选择的基础上进行贪心&#xff0c;做最优选择&#xff0c;除此之外&#xff0c;还得看局部最优会不会形成全局最优…

8 百度接口

0 建议学时 2学时 1 简介 百度人工智能平台-站在巨人的肩膀上 https://ai.baidu.com/ 控制台->立即注册 百度人工智能平台 APP Key 和 Secret Key AI接入指南 https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjgn3 百度智能云视频参考 https://abcxueyuan.baidu.com/#/…

2023年最新详细教程!手把手教你搭建Hexo + GitLab个人博客

文章目录前言一、安装和配置环境1.安装 Git2.安装 Node.js二、新建博客项目1.GitLab配置CI/CD自动化部署1.1 GitLab新建项目1.2 GitLab自建Runners1.2.1 下载gitlab-runner1.2.2 注册Runners1.2.3 安装Runners并启动1.3 添加.gitlab-ci.yml文件2.拉取和推送hexo blog2.1 拉取he…

基于遗传算法的配电网故障定位(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

sonarqube 外部扫描器 go vet golangci-lint 无法导入问题

首先&#xff0c;请看[外部分析报告]各种语言的报告生成 go vet 2> govet-report.out#没有golangci-lint&#xff0c;我从网上找到了 golangci-lint run --out-format checkstyle ./... > golangci-lint-report.xml值得注意的是&#xff0c;貌似不支持目录&#xff0c;仅…

6.2 负反馈放大电路的四种基本组态

通常&#xff0c;引入交流负反馈的放大电路称为负反馈放大电路。 一、负反馈放大电路分析要点 如图6.2.1(a)所示电路中引入了交流负反馈&#xff0c;输出电压 uOu_OuO​ 的全部作为反馈电压作用于集成运放的反向输入端。在输入电压 uIu_IuI​ 不变的情况下&#xff0c;若由于…

mysys2+minGW方案编译ffmpeg的最佳实践

一、Win10 64bit编译环境的建立1&#xff09;从http://www.msys2.org/下载 msys2-x86_64-xxx.exe2&#xff09; 安装msys2到默认路径 C:\msys64\3&#xff09; 运行MSYS2 w644&#xff09;执行 pacman -Syu 更新系统当出现提示时&#xff0c;选择y5) 当窗口关闭时&#xff0c;重…

JavaScript函数

目录 定义函数 调用函数 函数参数 函数返回值 匿名函数 箭头函数 使用JavaScript编程时&#xff0c;函数是一种非常有用的编程结构&#xff0c;用于执行特定的任务并返回结果。函数可以重复使用&#xff0c;因此您只需编写一次代码&#xff0c;即可在需要时多次调用该代码…

深入解析dubbo的延迟暴露

一、引子 最近搭建了一个新的Java工程&#xff0c;主要是提供dubbo服务给其他业务用的。突然想起之前dubbo服务都会配置延迟暴露来解决平滑发布的问题&#xff0c;但是好像现在新的Java项目都没有配置延迟暴露了&#xff0c;觉得很奇怪&#xff0c;所以去研究了一下关于dubbo延…