c++ 多线程 类成员函数_C++11多线程并发基础入门教程

本文介绍了C++11多线程并发的基础知识,包括线程创建、互斥量的使用、异步线程和原子类型。通过详细讲解和实例,阐述了线程池的概念及其优势,同时探讨了并发与并行的区别以及创建线程时的参数传递问题。此外,还强调了在使用多线程时避免资源浪费和管理线程的重要性。
摘要由CSDN通过智能技术生成

00a5d398b879199737ba2459a648b5fb.png

cb1ea1c584c25076c4ffdd34a09c26ed.png

最后一次更新日期:2020.10.11

因为想要将文章按照学习路径和知识的难易程度来排版,所以再在这篇文章中添加大量内容就违背了这个初衷了,因此新开了《C++11多线程并发基础入门教程-进阶版》,这篇文章只会做修订,以及在微调已有的内容,新的内容会跟新到另一篇文章。

zizbee:C++11多线程并发基础入门教程-进阶版​zhuanlan.zhihu.com


最近在看《C++ Concurrency in Action, Second Edition》这本书,有中文译本,新手或者有一定经验的人都比较适合看这本书,书中基础和提升都涉及到了,把内部的原理讲的很清晰,强烈推荐这本书!!!
我写教程一方面是分享下学习经验,另一方面是督促自己学习。
书中可能有许多不严谨的地方,写的过于严谨可能就不够简明了。
本人菜鸟,但自认为不一定要等着学成大佬才能开始写教程,一个人懂得太多,就容易忘记自己曾经不懂时候的样子,新手才能理解新手会在哪些方面存有疑惑。文章的排版顺序不是按照结构体系来排版的,而是按照学习路径和知识的难易程度来排版的。

1 什么是C++多线程并发?

线程:线程是操作系统能够进行CPU调度的最小单位,它被包含在进程之中,一个进程可包含单个或者多个线程。可以用多个线程去完成一个任务,也可以用多个进程去完成一个任务,它们的本质都相当于多个人去合伙完成一件事。

多线程并发:多线程是实现并发(双核的真正并行或者单核机器的任务切换都叫并发)的一种手段,多线程并发即多个线程同时执行,一般而言,多线程并发就是把一个任务拆分为多个子任务,然后交由不同线程处理不同子任务,使得这多个子任务同时执行。

C++多线程并发: C++98标准中并没有线程库的存在,而在C++11中终于提供了多线程的标准库,提供了管理线程、保护共享数据、线程间同步操作、原子操作等类,。(简单情况下)实现C++多线程并发程序的思路如下:将任务的不同功能交由多个函数分别实现,创建多个线程,每个线程执行一个函数,一个任务就这样同时分由不同线程执行了。

新手不要过多纠结多线程与多进程、并发与并行这些概念 (这些概念都是相当于多个人去合伙完成一件事),会用才是王道,理解大致意思即可,想要深入了解可阅读本文“延伸拓展”章节。

我们通常在何时使用并发? 程序使用并发的原因有两种,为了关注点分离(程序中不同的功能,使用不同的线程去执行),或者为了提高性能。当为了分离关注点而使用多线程时,设计线程的数量的依据,不再是依赖于CPU中的可用内核的数量,而是依据概念上的设计(依据功能的划分)。

知道何时不使用并发与知道何时使用它一样重要。 不使用并发的唯一原因就是收益(性能的增幅)比不上成本(代码开发的脑力成本、时间成本,代码维护相关的额外成本)。运行越多的线程,操作系统需要为每个线程分配独立的堆栈空间,需要越多的上下文切换,这会消耗很多操作系统资源,如果在线程上的任务完成得很快,那么实际执行任务的时间要比启动线程的时间小很多,所以在某些时候,增加一个额外的线程实际上会降低,而非提高应用程序的整体性能,此时收益就比不上成本。

2 C++多线程并发基础知识

2.1 创建线程

首先要引入头文件#include<thread>,C++11中管理线程的函数和类在该头文件中声明,其中包括std::thread类。

语句"std::thread th1(proc1);"创建了一个名为th1的线程,并且线程th1开始执行。

实例化std::thread类对象时,至少需要传递函数名作为参数。如果函数为有参函数,如"void proc2(int a,int b)",那么实例化std::thread类对象时,则需要传递更多参数,参数顺序依次为函数名、该函数的第一个参数、该函数的第二个参数,···,如"std::thread th2(proc2,a,b);"。这里的传参,后续章节还会有详解与提升。

只要创建了线程对象(前提是,实例化std::thread对象时传递了“函数名/可调用对象”作为参数),线程就开始执行。

总之,使用C++线程库启动线程,可以归结为构造std::thread对象。

那么至此一个简单的多线程并发程序就编写完了吗?

不,还没有。当线程启动后,一定要在和线程相关联的std::thread对象销毁前,对线程运用join()或者detach()方法。

join()与detach()都是std::thread类的成员函数,是两种线程阻塞方法,两者的区别是是否等待子线程执行结束。

新手先把join()弄明白就行了,然后就可以去学习后面的章节,等过段时间再回头来学detach()。一开始就钻的太深容易变成“从入门到入土”。

join在这里如果你按“加入”的翻译来理解,你就会比较疑惑它的用途,加入什么?这里我把它翻译为“等待”,join的用途就清晰明了,等待子线程运行结束,虽然这个翻译不那么正规,新手嘛,要啥自行车。

等待调用线程运行结束后当前线程再继续运行,例如,主函数中有一条语句th1.join(),那么执行到这里,主函数阻塞,直到线程th1运行结束,主函数再继续运行。

整个过程就相当于:你在处理某件事情(你是主线程),中途你让老王帮你办一个任务(与你同时执行)(创建线程1,该线程取名老王),又叫老李帮你办一件任务(创建线程2,该线程取名老李),现在你的一部分工作做完了,剩下的工作得用到他们的处理结果,那就调用"老王.join()"与"老李.join()",至此你就需要等待(主线程阻塞),等他们把任务做完(子线程运行结束),你就可以继续你手头的工作了(主线程不再阻塞)。

一提到join,你脑海中就想起两个字,"等待",而不是"加入",这样就很容易理解join的功能。

#include<iostream>
#include<thread>
using namespace std;
void proc(int a)
{
    cout << "我是子线程,传入参数为" << a << endl;
    cout << "子线程中显示子线程id为" << this_thread::get_id()<< endl;
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值