- 1、补充知识
- 1.1 虚假唤醒
- 1.2 atomic
- 2、浅谈线程池
- 2.1 场景设想
- 2.2 线程池
- 2.3 实现方式
- 3、谈线程池创建线程数量
- 3.1 线程开的数量极限问题
- 3.2 线程创建数量建议
- notify_one或者notify_all唤醒wait()后,实际有些线程可能不满足唤醒的条件,就会造成虚假唤醒,可以在wait中再次进行判断解决虚假唤醒。
- 解决:wait中要有第二个参数(lambda),并且这个lambda中要正确判断所处理的公共数据是否存在。
atomicatm; atm = 0; void ThreadA() { for (int i = 0; i < 1000000; i++) { atm += 1; //原子操作 } return; } void ThreadB() { while (true) { cout << atm << endl; //读atm是个原子操作,但是整个这行代码并不是一个原子操作 } //end while }
- 这里B线程中(第15行代码),只有读取atm是原子 *** 作,但是这一整行代码cout << atm << endl;并不是原子操作,这就会导致最终显示在屏幕上的值是一个“曾经值”。
atomicatm; atm = 0; auto atm2 = atm; //这种定义时初始化 *** 作不允许 atomic atm3; atm3 = atm; //这种拷贝赋值运算符也不让用
- 这里第三行代码,这种定义时初始化 *** 作不允许,显示“尝试引用已删除的函数”,说名编译器内部肯定把拷贝构造函数给干掉了。
- 第5行代码,这种拷贝赋值运算符也不让用。
atomicatm; atm = 0; atomic atm2(atm.load()); auto atm3(atm.load());
- 使用load()函数可以以原子方式读取atomic对象的值。
atomicatm; atm = 0; atomic atm2(atm.load()); atm2.store(12);
- 使用store()函数可以以原子方式写入内容。
原子 *** 作实质上是:不允许在进行原子对象 *** 作时进行CPU的上下文切换
2、浅谈线程池 2.1 场景设想- 服务器程序,每来一个客户端,就创建一个新线程为这个客户提供服务。
- 问题:
- 2万个玩家,不可能给每个玩家创建一个新线程,此程序写法在这种场景下不通。
- 程序稳定性问题:编写代码中,“时不时地突然”创建一个线程,这种写法,一般情况下不会出错,但是不稳定的;
- 线程池:把一堆线程弄到一起,统一管理。这种统一管理调度,循环利用的方式,就叫做线程池。
- 程序启动时,一次性创建好一定数量的线程。这种方式让人更放心,觉得程序代码更稳定。
- 一般来讲,2000个线程基本就是极限;再创建就会崩溃。
- 当采用某些技术开发程序,一定要根据API接口提供商的建议,比如创建线程数量为CPU的线程数量,或者CPU线程数量乘2,再或者CPU线程数量乘2再加2,等等。一定要遵照专业建议和指示来,专业意见确保程序高效执行。
- 创建多线程完成业务:考虑可能被阻塞的线程数量,创建多于最大被阻塞线程数量的线程,如100个线程被阻塞再充值业务,开110个线程就是很合适的。
- 线程创建数量尽量不要超过500个,尽量控制在200个之内;
注:本人学习c++多线程视频地址:C++多线程学习地址
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)