通过几次修改,我们现在可以愉快的交流了。但是当用户越来越多的时候,我们发现,服务器顶不住了,人太多了,消息完全处理不过来。发了个消息,三年后对方才收到,于是我们想着给他"多整几个CPU",让他多些线路去处理消息
首先 让我们看看什么是线程
线程(thread, 台湾称"执行绪")是"进程"中某个单一顺序的控制流。也被称为轻量进程(lightweight processes)。计算机科学术语,指运行中的程序的调度单位。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程。
要弄清楚线程,须结合进程加以理解:
进程是一个可执行的程序,由私有虚拟地址空间、代码、数据和其他操作系统资源(如进程创建的文件、管道、同步对象等)组成。一个应用程序可以有一个或多个进程,一个进程可以有一个或多个线程,其中一个是主线程。
线程是操作系统分时调度分配CPU时间的基本实体。一个线程可以执行程序的任意部分的代码,即使这部分代码被另一个线程并发地执行;一个进程的所有线程共享它的虚拟地址空间、全局变量和操作系统资源。之所以有线程这个概念,是因为以线程而不是进程为调度对象效率更高:由于创建新进程必须加载代码,而线程要执行的代码已经被映射到进程的地址空间,所以创建、执行线程的速度比进程更快。
一个进程的所有线程共享进程的地址空间和全局变量,所以简化了线程之间的通讯。
我们现在知道了线程是什么,而我们的目的是使用多个线程来执行事件。那么,多线程是什么?
假如操作系统本身支持多个处理器,那么每个线程都可分配给一个不同的处理器,真正进入“并行运算”状态。从程序设计语言的角度看,多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程;假如机器本身安装了多个处理器,那么程序会运行得更快,毋需作出任何特殊的调校。根据前面的论述,大家可能感觉线程处理非常简单。但必须注意一个问题:共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到一个问题。举个例子来说,两个线程不能将信息同时发送给一台打印机。为解决这个问题,对那些可共享的资源来说(比如打印机),它们在使用期间必须进入锁定状态。所以一个线程可将资源锁定,在完成了它的任务后,再解开(释放)这个锁,使其他线程可以接着使用同样的资源。
多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
现在知道了多线程的概念,让我们来看一下如何去实现多线程执行
####创建一个线程的容器,只需要一个简单的循环就可以将io_service放在不同的线程中去执行###
std::vector<std::thread> threadGroup;
for(int i = 0; i < 5; ++i) {
threadGroup.emplace_back([&io_service, i]{
io_service.run();});
}
线程的销毁也是同样
for(auto& v : threadGroup) v.join();
客户端也保持同步
使用多个线程去跑io_service
for(int i = 0; i < 5; ++i) {
clientGroup.emplace_back(std::make_unique<chat_client>(
io_service, endpoint_iterator));
}
std::thread t([&io_service]() { io_service.run(); });
同样的去关闭线程
for(auto& v: clientGroup)
v->close();
**到现在,多线程就算是实现了,但是在运行过程中又发现了新的问题,有时候,两个或者多个线程会去争抢一个消息,然后你不给我,我不给你,最终线程死等。
解决这种问题最简单的方法就是加锁,也就是锁住某个事件动作,只能让一个线程去执行他,等他执行完了才解锁,等待下一个事件动作。
boost提供了这样的函数 — strand
strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. io_service不能保证线程安全
列:
void chat_room::deliver(const chat_message &msg) {
m_strand.post
([this, msg]
只需要把读写和分发操作保护起来,线程就不会再并发实行,再次测试,可以安全的交流了