1. C++使用Thread类创建多线程的三种方式

news2024/11/15 9:58:27

1. 说明

使用Thread类创建线程对象的同时就会立刻启动线程,线程启动之后就要明确是等待线程结束(join)还是让其自主运行(detach),如果在线程销毁前还未明确上面的问题,程序就会报错。一般都会选择等待线程执行结束,如果不等待线程,即让其与主线程分离自主运行,那必须保证线程结束之前,可访问数据的有效性。
注意:当主线程碰到了子线程调用join()函数,程序会阻滞在当前行等待,直到当前子线程执行结束才会继续执行下面的代码。如果有多个线程需要同时执行,需要将每个线程的join()函数放到主线程的最后,才能避免阻滞现象。

2. 创建线程

使用thread类创建线程,主要有三种方式:①使用普通函数创建,②使用自定义类创建,③使用Lambda表达式创建

2.1 使用普通函数创建

此种方式,只是将普通函数的名字传输到thread构造函数中,注意不要再函数名字后面带()。

#include <iostream>
using namespace std;

#include <thread>

void myPrint() 
{
    cout << "我的线程开始执行了..." << endl;

    cout << "我的线程执行完毕了..." << endl;
}

int main()
{
    thread myThread(myPrint);//创建线程对象,并启动线程

    myThread.join();//等待子线程执行结束后,再执行下面的代码
	//myThread.detach();  //子线程与主线程分离,各自执行,互不影响(但子线程如果使用了主线程中的数据,当主线程结束后,子线程无法访问到数据时,会报错)

    std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;

    return 0;
}

2.2 使用自定义类创建

这种方法需要重载()运算符,把子线程需要执行的代码写到里面即可。而且此种方法将类对象名传输到thread类构造函数中后,实际上时调用了自定义类的拷贝构造函数复制了一份,线程执行结束后会调用自定义类的析构函数。

#include <iostream>
using namespace std;

#include <thread>

class background_task
{
public:
	//构造函数
    background_task()
    {
        cout << "这里时构造函数...." << endl;
    }
	//拷贝构造函数
    background_task(const background_task& bg)
    {
        cout << "执行了拷贝构造函数...." << endl;
   }
	//析构函数(此案例中析构函数被调用两次,具体解释在下面)
   ~background_task()
   {
       cout << "执行了析构函数...." << endl;
   }
	//重载()运算符,将子线程需要执行的代码写入其中
   void operator()() const
   {
       //在这里写子线程要执行的代码
       cout << "我的线程开始执行...." << endl;

       cout << "我的线程执行结束了...." << endl;
   }
};

int main()
{
    background_task f;//创建类对象(主线程结束后销毁此对象,会调用一次析构函数)
    thread my_thread(f);//创建线程对象,并启动线程(线程结束后,在子线程空间内通过拷贝构造函数创建的对象也会被销毁,也会调用一次析构函数)
    my_thread.join();
    
    std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;

    return 0;
}

程序输出结果:
在这里插入图片描述

2.3 使用Lambda表达式创建

这种方式创建比较简单,但是子线程中的代码不易重复使用


#include <iostream>
using namespace std;

#include <thread>

int main()
{
    //使用lambda表达式创建线程

    thread my_thread([] {

        cout << "lambda表达式创建的线程开始执行....\n" << endl;

        cout << "lambda表达式创建的线程执行结束....\n" << endl;

        });

    my_thread.join();

    std::cout << "主线程收尾,最终主线程安全正常退出...\n"<<endl;

    return 0;
}

3 扩展:

①:
子线程调用join()函数时,可以先使用joinable()函数判断是否能够加入,一个子线程只能加入一次,若能加入则返回true,否则返回false.

#include <iostream>
using namespace std;

#include <thread>

void myPrint() 
{
    cout << "我的线程开始执行了..." << endl;

    cout << "我的线程执行完毕了..." << endl;
}

int main()
{
    thread myThread(myPrint);//创建线程对象,并启动线程
	
	if(myThread.joinable())
	{
		cout << "子线程能够使用join()或者detach()函数" << endl;
		myThread.join();//等待子线程执行结束后,再执行下面的代码
	}
	else
	{
		cout << "子线程不能够使用join()或者detach()函数" << endl;
	}
    std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;
    return 0;
}

②:
当有多个子线程需要同时进行时,最好将子线程的join()函数调用放到所有子线程的后面,这样能确保子线程之间不会等待


#include <iostream>
using namespace std;

#include <thread>

int main()
{
    //使用lambda表达式创建线程

    thread my_thread_1([] {

        cout << "lambda表达式创建的线程 1 开始执行....\n" << endl;

        cout << "lambda表达式创建的线程 1 执行结束....\n" << endl;

        });
    //my_thread_1.join();//如果在这里调用join,则子线程1执行结束后才能执行子线程2,因为join函数会阻塞后面的代码执行
    thread my_thread_2([] {

        cout << "lambda表达式创建的线程 2 开始执行....\n" << endl;

        cout << "lambda表达式创建的线程 2 执行结束....\n" << endl;

        });
    
    my_thread_1.join();
    my_thread_2.join();

    std::cout << "主线程收尾,最终主线程安全正常退出...\n"<<endl;

    return 0;
}

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

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

相关文章

webserve简介

目录 I/O分类I/O模型阻塞blocking非阻塞 non-blocking&#xff08;NIO&#xff09;IO复用信号驱动异步 webServerHTTP简介概述工作原理HTTP请求头格式HTTP请求方法HTTP状态码 服务器编程基本框架两种高效的事件处理模式Reactor模式Proactor模拟 Proactor 模式 线程池 I/O分类 …

字节岗位薪酬体系曝光,看完感叹:不服真不行

曾经的互联网是PC的时代&#xff0c;随着智能手机的普及&#xff0c;移动互联网开始飞速崛起。而字节跳动抓住了这波机遇&#xff0c;2015年&#xff0c;字节跳动全面加码短视频&#xff0c;从那以后&#xff0c;抖音成为了字节跳动用户、收入和估值的最大增长引擎。 自从字节…

最全MySQL8.0实战教程

文章目录 最全MySQL8.0实战教程一.前言1.计算机语言概述2.SQL的概述2.1 语法特点2.2 MySQL的安装2.2.1 方式1&#xff1a;解压配置方式2.2.2 方式2&#xff1a;步骤安装方式 二. 数据库DDL操作1.DDL概念2.对数据库常用操作 最全MySQL8.0实战教程 长路漫漫&#xff0c;键盘为伴&…

【Linux进阶篇】启动流程和服务管理

目录 &#x1f341;系统启动 &#x1f343;Init和Systemd的区别 &#x1f343;运行级别和说明 &#x1f341;Systemd服务管理 &#x1f343;6和7命令区别 &#x1f343;systemd常用命令 &#x1f341;系统计划调度任务 &#x1f343;一次性任务-at &#x1f343;batch &#x1…

论文 : Multi-Channel EEG Based Emotion Recognition Using TCNBLS

Multi-Channel EEG Based Emotion Recognition Using Temporal Convolutional Network and Broad Learning System 本文设计了一种基于多通道脑电信号的端到端情绪识别模型——时域卷积广义学习系统(TCBLS)。TCBLS以一维脑电信号为输入&#xff0c;自动提取脑电信号的情绪相关…

自然语言处理 —— 01概述

什么是自然语言处理呢? 自然语言处理就是NLP,全名为Natural Language Processing。 一、NLP的困难 1. 歧义 (1)注音歧义 (2)分词歧义 (3)结构歧义 (4)指代歧义 (5)语义歧义 (6)短语歧义

javascript简单学习

简介&#xff1a; javascript 是脚本语言 javascript是轻量级的语言 javascript是可插入html页面的编程代码 javascript插入html页面后&#xff0c;可由所有现代浏览器执行 以下是JavaScript的一些基本概念&#xff1a; 1. 变量&#xff1a;变量用于存储数据值&#xff0…

每日学术速递4.13

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Slide-Transformer: Hierarchical Vision Transformer with Local Self-Attention(CVPR 2023) 标题&#xff1a;Slide-Transformer&#xff1a;具有局部自注意力的分层视觉变换器 …

一、vue之初体验-两种方式引入vue

一、Vue引入方式-CDN <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevice-width, initial-s…

开源问答社区软件Answer

什么是 Answer &#xff1f; Answer 是一个开源的知识型社区软件。您可以使用它快速建立您的问答社区&#xff0c;用于产品技术支持、客户支持、用户交流等。 Answer是国内SegmentFault 思否团队开发的技术问答社区&#xff0c;Answer 不仅拥有搭建问答平台&#xff08;Q&A…

界面控件DevExtreme使用指南 - 折叠组件快速入门(一)

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

MySQL - C语言接口-预处理语句

版权声明&#xff1a;本文为CSDN博主「zhouxinfeng」的原创文章&#xff0c;原文链接&#xff1a;https://blog.csdn.net/zhouxinfeng/article/details/77891771 目录 MySQL - C语言接口-预处理语句预处理机制特点&#xff1a;预处理机制数据类型函数:预处理机制步骤&#xff1…

集群聊天服务器项目(三)——负载均衡模块与跨服务器聊天

负载均衡模块 为什么要加入负载均衡模块 原因是&#xff1a;单台服务器并发量最多两三万&#xff0c;不够大。 负载均衡器 Nginx的用处或意义**&#xff08;面试题&#xff09;** 把client请求按负载算法分发到具体业务服务器Chatserver能和ChatServer保持心跳机制&#xf…

机器学习实战5-天气预测系列:利用数据集可视化分析数据,并预测某个城市的天气情况

大家好&#xff0c;我是微学AI&#xff0c;最近天气真的是多变啊&#xff0c;忽冷忽热&#xff0c;今天再次给大家带来天气的话题&#xff0c;机器学习实战5-天气预测系列&#xff0c;我们将探讨一个城市的气象数据集&#xff0c;并利用机器学习来预测该城市的天气状况。该数据…

迈入Java,一文告诉你学习Java的原因

前言 Java是一种流行的编程语言&#xff0c;由Sun Microsystems于1995年首次发布。自那时以来&#xff0c;Java已成为全球最广泛使用的编程语言之一。Java具有许多优点&#xff0c;包括跨平台、面向对象和安全性等&#xff0c;使其成为开发企业软件、Web应用程序和移动应用程序…

Consul TTL健康检查方式

consul比较常用的健康检查方式为http健康检查方式&#xff0c;也还有使用TTL方式来进行健康检查的&#xff0c;下面从spring-cloud-consul-discovery这个SDK来着手分析。 构建ConsulAutoRegistration&#xff0c;这里的工作是组成服务注册的报文&#xff0c;有一个setCheck方法…

【应急响应】战中溯源反制对抗上线CSGoby蚁剑Sqlmap等安全工具

文章目录 溯源反制-Webshell工具-Antsword正常情况下&#xff0c;PHP后门上线发现PHP后门&#xff0c;修改webshell进行反制 溯源反制-SQL注入工具-SQLMAP溯源反制-漏洞扫描工具-Goby&Awvs溯源反制-远程控制工具-CobaltStrike1、伪造流量批量上线&#xff08;欺骗防御&…

(IPC)进程间通信的常用的两种方式——管道、共享内存

前言&#xff1a; 众所周知&#xff0c;不同的进程之间&#xff0c;在正常情况下&#xff0c;由于其拥有独立的PCB、上下文等原因&#xff0c;每个进程都是独立且互不干扰&#xff0c;这不仅保证了进程的安全&#xff0c;也降低了OS对于进程的管理成本。 但是通常情况下&…

第04讲:实战掌握 Byte Buddy,体验代码生成的顺畅

为什么需要运行时代码生成 我们知道&#xff0c;Java 是一种强类型的编程语言&#xff0c;即要求所有变量和对象都有一个确定的类型&#xff0c;如果在赋值操作中出现类型不兼容的情况&#xff0c;就会抛出异常。强类型检查在大多数情况下是可行的&#xff0c;然而在某些特殊场…

猴子分桃与反转部分单链表

目录 一、编程题 1.猴子分桃 2.反转部分单向链表 二、选择题 1.如果希望监听 TCO 端口 9000&#xff0c;服务器端应该怎样创建 socket&#xff1f; 2. jre 判断程序是否执行结束的标准是&#xff08; &#xff09; 一、编程题 1.猴子分桃 链接&#xff1a;猴子分桃__…