c++11多线程课堂笔记

上课地址:https://www.bilibili.com/video/BV1Yb411L7ak?p=2
第一节:1.进程就是一个可执行程序运行起来。每个进程都有一个主线程,这个主线程是唯一的。主线程和进程是唇齿相依的关系。线程可以理解为执行代码的道路。可以通过写代码创建其他线程。
2.每个线程都要独立的堆栈(1M),切换线程需要代价。主线程是自动启动
3.进程间通信:相同电脑 管道,文件,消息队列,共享内存
不同电脑:socket
4.一个进程中所有线程共线地址空间(内存)。全局变量,指针,引用都可以在进程中传递。带来一个问题:数据一致性问题,不同进程写同一数据。
5.线程优点:轻量级,速度快,开销小
6.c++11本身对多线程支持,意味着可移植
第二节
7.join和detach作用相反,一个主线程等待子线程,一个不等待。一个子线程join或者detach后就不能再join或者detach,会导致joinable为false
8.detach的子线程就会与主线程失去关联,就是驻留在后台运行,被c++运行时库接管。会失去控制
9.joinable判断是否可以用join或者detach,返回true或者false
10.创建线程的办法:lambda,函数对象,函数。函数对象的时候要传值,不能传引用,因为主线程结束后子线程还在运行就无对象可传。
第三节:
11.创建线程的同时构造临时对象的方法传递参数是可行的
第四节:
12.创建多个线程注意:全部只读是安全的,有读有写不行。最简单的不崩溃处理方法是,读的时候不能写,写的时候不能读。
13.list频繁的按顺序插入和删除数据效率高。vector随机插入和删除效率高
第五节:
14.互斥量,mutex中的lock和unlock,需要成对使用。
15.使用lock_guard 代替lock和unlock。智能指针类似
16.死锁:必须至少有两个锁头,上锁的先后顺序不一致导致。解决方法:上锁的顺序一致。使用std::lock(),一次锁住多个互斥量,原理是要么都锁要么都不锁,如果一个没锁住,另外一个会立马解锁。但是lock很少用到
17.把lock_guard和lock混合使用,就可以不需要写unlock。可以实现既不死锁也不会忘了写unlock
第六节:
18.unique_lock代替lock_guard:前者效率差,占用内存多,但是灵活。前者有try_to_lock(第二个参数)当拿不到锁的时候会尝试继续拿锁,不会卡住。
19.unique_lock第二个参数三种:adopt_lock,对已加锁的废弃加锁
try_to_lock对未加锁的不停尝试加锁
defer_to_lock延迟到自己想加锁的地方
20.unique_lock的成员函数:lock,unlock,try_lock,release。
release释放锁的所有权,和unlock不一样。只能转移所有权不能复制所有权,使用std::move 移动所有权。
第七节:
21.单例模式:某些特殊的类,该对象只有一个。双重锁用于单例模式解决数据共享问题
22.call_once函数,保证某函数只能被调用一次,效率高,需要和标记结合使用once_flag
23.双重锁定
第八节:
1.condition_variable条件变量,实际上是个类,notify_once和wait配合使用,调用notify_once会唤醒wait,根据wait的第二个参数决定是否继续执行
2.notify_all 唤醒多个线程,但是只有一个能拿到锁
第九节:
23.async 可以从线程返回一个值,是个函数模板用来启动一个异步任务,之后返回future对象。启动一个异步任务就是创建一个线程并执行,这个future对象里面就有返回的结果,通过get成员函数获得结果。这个结果可能没法立即拿到,但是在不久的将来能拿到
24.通过向async传递参数。1.launch::deferred,延迟到调用wait和get的时候才创建 2.launch::async,立马创建线程,缺省值就是async
25.packaged_task的使用
26.promise作用:可以从没有返回值的线程中拿值。和future一起使用,可以实现不同线程之间通信
27.浅拷贝,深拷贝,share_ptr, ref和&
27.1浅拷贝和深拷贝只针对指针而言(自己总结的)
27.2 字符串的拷贝和复制问题。
1)使用strcpy_s是第二个参数指定大小时要加一,memcpy第三个参数一样要加一。
2)char* p=new char[6];p=“Hello”;这种写法是错的!!!应该用strcpy_s。
3)char * p=new char(“Hello”); 这种写法也是错的,不能用字符串来初始化字符
4)诸如 int* a ;* a = 1; char * a; * a = ‘a’;这种写法是错的,空地址不能赋值
5)char * aa =(char*)“asd”;这是可以的
6)student s4 = s3;调用的是拷贝构造!!并非拷贝赋值,因为这是创建对象
7)student s4 = s3; s4=s1;后面那个才是调用拷贝赋值,拷贝赋值是对已有的对象进行赋值。
8)shared_ptr在reset时会使得原来的计数器减一
9)对于thread传参数,参考
https://www.cnblogs.com/chen-cs/p/13056703.html
1、使用引用和指针是要注意;
  2、对于内置简单类型,建议传值;
  3、对于类对象,建议使用引用来接收,使用引用会只会构造两次,而传值会构造三次,使用ref()传只会调用一次,使用临时对象会调用两次
  4、在detach下要避免隐式转换,因为此时子线程可能还来不及转换主线程就结束了,应该在构造线程时,用参数构造一个临时对象传入。
10)std::move 强制把左值转成右值,std::forward,std::bind,std::function

第十节
28.async异步一直会等到自己结束主线程才会结束,这一点和thread不一样。并且如果是deferred模式,子线程还是在主线程中执行,此时线程id一样。
29.shared_future和future,前者get后还能继续get,后者不行,只能get一次,因为使用了move,导致变空。
30.atomic原子操作,理解成不需要互斥量加锁的技术解决多线程并发。原子操作就是多线程中不会被打断的程序执行片段。原子操作的效率比互斥量高。互斥量加锁一般多行代码,原子操作一般针对一个变量而不是代码段。
31.原子操作要么完成要么没开始,没有中间状态。一般用于统计发送多少数据包。
第十一节
32.++,–,+=,-=等才能支持原子操作,有的不支持,自己测试。atomia;a=a+1;就不支持原子操作
33.如果系统资源不足,调用thread时可能出错,报异常。而且thread取返回值不太容易。async由于资源紧张无法创建新线程时,就会在主线程中执行
34.async可以延迟创建任务,async和thread最明显的不同是,async有时候并不一定创建线程。
35.async如果不带第一个参数,默认值是launch::deferred | launch::async
第九节讲错了,这个默认值的效果可能和launch::deferred一样也可能和 launch::async一样
36.异步指创建新线程,同步指不创建新线程
37.async叫创建异步任务,不一定创建新线程
第十二节
38.Windows的临界区和互斥量类似。是Windows.h里的,只能在win平台上用。但是c++11里的多线程可以跨平台。
39.win中的CRITICAL_SECTION使用需要初始化
40.同一个线程中使用多次进入相同临界区是可以的,不过也要相同次数离开临界区。但是mutex不可以这样。
41.win没有自动析构,比如lock_guard这样,但是自己可以写个class,构造进入临界区,析构离开临界区。这种写法叫做RALL
42.recursive_mutex 递归的独占互斥量,可以在一个线程中多次上锁。
43.超时的互斥量timed_mutex,提供try_lock_for,try_lock_unti,如果在某段时间里没拿到锁或者拿到锁会干什么
44.recursive_timed_mutex
第十三节
45.虚假唤醒:把你唤醒了却做了没有意义的事。 先理解好第八节的notify_one,notify_all
46.atomic:初始化需要注意
47:.线程池:两万个玩家该怎么创建服务器线程。把一堆线程弄到一起统一管理,循环利用线程。
实现方式:在程序启动时,一次性创建好一定数量的线程。几十几百个,极限2000个。尽量不要在程序执行过程中创建线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值