# multiThread **Repository Path**: youqian04/multi-thread ## Basic Information - **Project Name**: multiThread - **Description**: C++11手撕多线程 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-28 - **Last Updated**: 2024-04-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 手撕多线程 ~~~ 时间:2024.04.28 内容:使用C++11手撕多线程,以学习多线程 如代码有问题,请联系hiyouqian@163.com,欢迎一起讨论,共同学习 ~~~ ## 介绍 跟着B站视频 [C++11 多线程编程-小白零基础到手撕线程池](https://www.bilibili.com/video/BV1d841117SH?p=1&vd_source=30472f5d61867be4dd61dd8d0251a776) 学习多线程,代码全程手敲并理解消化其原理 ## Problem 1 学习线程的使用以及阻塞 1. 创建线程给线程传递参数,直接在后面带参数 ~~~c++ thread thread1(printMsg, "Hello Thread"); ~~~ 2. join() 让主线程等待其他线程执行完毕之后再结束 join()是阻塞的,线程执行完之后才会执行join()后面的 3. detach() 将主线程和子线程分离,子线程在后台运行 4. joinable() 判断线程是否能调用join()或detach(),返回一个布尔值,以防报错 ## Problem 2 线程中数据未定义错误 1. 传递引用类型不能用临时变量 thread t(foo, a);不可以,会报错 thread t(foo, ref(a));正确 2. 传递指针或引用的时候,要注意变量是不是局部变量,是否存在内存被释放掉的问题 3. 私有成员函数作为线程入口函数,需要使用 友元函数 ## Problem 3 互斥量解决多线程数据共享问题 1. 多个线程访问共享数据,会出现数据共享问题 为了保证正确性,需要对共享数据加锁,mutex声明一个互斥量mtx,使用前lock()加速,用完后unlock()解锁 ## Problem 4 互斥量死锁问题 1. A和B拥有对方要访问的资源,但都要拥有对方的资源才释放,引起相互等待的过程,从而产生死锁 解决办法:改变资源访问顺序,以同一顺序访问资源 ## Problem 5 lock_guard和unique_lock 1. lock_guard是互斥量封装类,用于保护共享数据,防止多个线程同事访问同一资源导致数据竞争问题 构造函数被调用,自动加锁;析构函数被调用,自动解锁 lock_guard对象不能拷贝/移动(禁用拷贝构造),只在局部作用域中使用 2. unique_lock是互斥量封装类,包括延迟加锁、条件变量、超时等 可自动加锁,可延迟加锁 构造加上defer_lock,构造了但没加锁,需要手动加锁,析构的时候会解锁 try_lock_for等待给定时间,获取不到锁就返回 try_lock_until超过给定时间,获取不到锁就返回 unique_lock对象不能拷贝/移动(禁用拷贝构造),支持右值引用转换和swap()转换 ## Problem 6 call_once使用场景 1. 单例实例是全局唯一的,初始化只能初始化一次,在多线程中使用,需要使用call_once 2. call_once只能在多线程中使用,多个线程执行到call_once时,只保证让一个线程去执行 ## Problem 7 condition_variable使用场景 1. condition_variable使用 创建对象 创建一个互斥锁mutex,保护共享资源的访问 在需要等待条件变量的地方添加unique_lock,并调用condition_variable::wait()、condition_variable::wait_for()、condition_variable::wait_until()函数等待变量 在其他线程中需要通知等待的线程,调用condition_variable::notify_one()、condition_variable::notify_all() ## Problem 8 线程池 1. 创建线程池,让线程循环去任务队列取任务 涉及:右值引用(移动语义、完美转发)、模板函数、lambda表达式等C++11新特性 ## Problem 9 异步并发 1. async用于异步执行一个函数,并返回future对象,表示异步操作的结果 async可以方便地进行异步编程,避免手动创建线程和管理线程 2. packaged_task将函数或可调用对象转换成一个异步操作,供其他线程使用 packaged_task封装的线程,需要手动创建开启线程,开启线程时需要使用移动语义move() 流程:首先封装对象--获取future对象--手动创建线程--从future对象中获取结果 3. promise用于在一个线程中产生一个值,在另外一个线程中获取所产生的值 流程:首先定义promise对象--通过传引用ref()传给一个线程--获取future对象--创建线程设置value--从future对象中获取结果 ## Problem 10 atomic原子操作 1. atomic实现对共享变量的操作,对个线程对atomic变量操作时,不会出现数据竞争的现象 load()返回atomic对象的值,store()修改atomic对象的值,保证是原子操作