为什么需要多线程?
最简单的多线程长啥样?
为什么需要线程池,有什么问题?
实现的主要原理是什么?
带着这几个问题,我们依次展开。
1.为什么需要多线程?
大部分程序毕竟都不是计算密集型的,简单的说,正常情况下,以单线程的模式来写对程序员而言是最舒心的。因为所有的代码都是顺序执行,非常容易理解!函数一级一级往下调用,代码一行一行执行。但是,代码的世界里,虽然cpu还好,但是却经常需要用到io资源,或者是其他服务器的网络资源,比如像数据库,如果这个时候因此把进程卡住,不管是客户端还是客户端都对用户体验相当糟糕。当然了,计算密集型的运算就更需要多线程,防止主线程被卡住。
2.最简单的多线程长啥样?
举个最简单的例子,服务器采用阻塞式socket,有一个网络线程负责收发包(IO),然后有一个逻辑主线程负责相应的业务操作,主线程和网络线程之间通过最简单的消息队列进行交换,而这个消息队例明显是两个线程都要访问(轮询消息队列是否为空)到的,所以,我们需要给这个消息队列上锁(std::mutex),即可以解决问题。由于比较简单我们就不需要看这个怎么码了。这种模式虽然简单,但是在合适的岗位上,也是极好的!
3.那为什么需要线程池呢,有什么问题?
还以刚才的服务器举例,如果业务线程逻辑比较复杂,又或者他需要访问数据库或者是其他服务器的资源,读取文件等等呢?当然他可以采用异步的数据库接口,但是采用异步意味着业务代码被碎片化。异步是典型的讨厌他,但是又干不掉他的样子。离题了。回归。这个时候我们需要多个业务线程处理了。多个线程就意味着多一份处理能力!回到上个问题,我们的多线程采用轮询消息队列的方式来交换信息,那么这么多个线程,不断的上锁解锁,光这个成本就够了。这个时候,条件变量就上线了(std::condition_variable)就登场了
4.实现的主要原理是什么?
业务线程不要轮询消息队列了,而所有的业务线程处于等待状态,当有消息再来的时候,再由产生消息的人,在我们示例场景就是网络线程了,随便唤醒一个工人线程即可。看看最关键的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
算了,还是直接贴完整代码,看注释吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
|
写一个类继承一下,并写一个工作函数和回调函数处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
|