1、实现多线程方法:
其实就是多个线程同时调用io_service::run
for(int i = 0; i < iThreads; i++){//创建线程,函数体是CIoService::run
CThreadPtr oThreadPtr(new CThread(boost::bind(&CIoService::run, &oIoSrv)));
vecThreads.push_back(oThreadPtr);
}
2、多线程调度情况:
asio规定:只能在调用io_service::run的线程中才能调用事件完成处理器。
注:事件完成处理器就是你async_accept、async_write等注册的句柄,类似于回调的东西。
单线程:
如果只有一个线程调用io_service::run,根据asio的规定,事件完成处理器也只能在这个线程中执行。也就是说,你所有代码都在同一个线程中运行,因此变量的访问是安全的。
多线程:
如果有多个线程同时调用io_service::run以实现多线程并发处理。对于asio来说,这些线程都是平等的,没有主次之分。如果你投递的一个请求比如async_write完成时,asio将随机的激活调用io_service::run的线程。并在这个线程中调用事件完成处理器(async_write当时注册的句柄)。如果你的代码耗时较长,这个时候你投递的另一个async_write请求完成时,asio将不等待你的代码处理完成,它将在另外的一个调用io_service::run线程中,调用async_write当时注册的句柄。也就是说,你注册的事件完成处理器有可能同时在多个线程中调用。
当然你可以使用 boost::asio::io_service::strand让完成事件处理器的调用【当处理函数不是线程安全的,强烈建议使用这种方式】,在同一时间只有一个, 比如下面的的代码:
socket_.async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
boost::bind(&connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
...
boost::asio::io_service::strand strand_;
此时async_read_some完成后调用handle_read时,必须等待其它handle_read调用完成时才能被执行(async_read_some引起的handle_read调用)。
多线程调用时,还有一个重要的问题,那就是无序化。比如说,你短时间内投递多个async_write,那么完成处理器的调用并不是按照你投递async_write的顺序调用的。asio第一次调用完成事件处理器,有可能是第二次async_write返回的结果,也有可能是第3次的。使用strand也是这样的。strand只是保证同一时间只运行一个完成处理器,但它并不保证顺序。
代码测试:
服务器:
将下面的代码编译以后,使用cmd命令提示符下传人参数
比如:BoostPro.exe 0.0.0.0 4321 3
客服端 使用windows自带的telnet
cmd命令提示符:
telnet 127.0.0.1 4321
原理:客户端连接成功后,同一时间调用20次boost::asio::async_write给客户端发送数据,并且在完成事件处理器中打印调用序号,和线程ID。
测试代码实现如下:
#include
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
using namespace boost;
typedef boost::shared_ptr CStrPtr;
typedef boost::thread CThread;
typedef boost::shared_ptr CThreadPtr;
class CTcpConn;
typedef boost::shared_ptr CTcpConnPtr;
typedef boost::mutex CMutex;
typedef boost::mutex::scoped_lock CScopedLock;
typedef boost::asio::io_service CIoService;
typedef boost::asio::ip::tcp::socket CSocket;
typedef boost::asio::ip::tcp::acceptor CAcceptor;
typedef boost::asio::ip::tcp::resolver CResolver;
typedef boost::asio::ip::tcp::resolver::query CQuery;
typedef boost::asio::ip::tcp::resolver::iterator CIterator;
typedef boost::asio::ip::tcp::endpoint CEndPt;
class CTcpConn : public boost::enable_shared_from_this{
private:
CMutex oMutex;
CSocket oSocket;
public:
CTcpConn(CIoService &iosrv) : oSocket(iosrv){}
static CTcpConnPtr CreateTcpConn(CIoService& iosrv){return CTcpConnPtr(new CTcpConn(iosrv));}
void Start(){
for(int i = 0; i < 20; i++){
CStrPtr oStrPtr(new string);
*oStrPtr = boost::lexical_cast(boost::this_thread::get_id()); *oStrPtr += "\r\n";
boost::asio::async_write(oSocket,boost::asio::buffer(*oStrPtr),
boost::bind(&CTcpConn::WriteHandler, shared_from_this(),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, oStrPtr, i));
}
}
CSocket& GetSocket(){return oSocket;}
private:
void WriteHandler(const boost::system::error_code& errorcode, std::size_t transferredbytes, CStrPtr oStrPtr, int index){
CScopedLock oScopedLock(oMutex);
if(!errorcode) cout << "SendSeq : " << index << ", ThreadId : " << boost::this_thread::get_id() << endl;
else cout << "Connections Unavailable !" << endl;
}
};
class CServer : private boost::noncopyable{
private:
CIoService oIoSrv;
CAcceptor oAcceptor;
std::size_t iThreads;
std::vector vecThreads;
public:
CServer(string& ip, string& port, int threads) : oAcceptor(oIoSrv), iThreads(threads){
CResolver oResolver(oIoSrv);
CQuery oQuery(ip, port);
CIterator oIterator = oResolver.resolve(oQuery);
CEndPt oEndPt = *oResolver.resolve(oQuery);
//打开、选项、绑定并监听
oAcceptor.open(oEndPt.protocol());
oAcceptor.set_option(CAcceptor::reuse_address(true));
oAcceptor.bind(oEndPt);
oAcceptor.listen();
//异步监听
StartAccepting();
}
~CServer(){Stop();}
void StartAccepting(){//接收来自客户端【telnet】的TCP连接
CTcpConnPtr oTcpConnPtr = CTcpConn::CreateTcpConn(oAcceptor.get_io_service());
oAcceptor.async_accept(oTcpConnPtr->GetSocket(), boost::bind(&CServer::AcceptHandler, this,
boost::asio::placeholders::error, oTcpConnPtr));
}
void AcceptHandler(const boost::system::error_code& errorcode, CTcpConnPtr oNewTcpConnPtr){
if(!errorcode) oNewTcpConnPtr->Start();
StartAccepting();
}
void Start(){
for(int i = 0; i < iThreads; i++){//创建线程,函数体是CIoService::run
CThreadPtr oThreadPtr(new CThread(boost::bind(&CIoService::run, &oIoSrv)));
vecThreads.push_back(oThreadPtr);
}
}
void Stop(){
oIoSrv.stop();//停止服务;等待所有线程结束
for(std::vector::iterator it = vecThreads.begin(); it != vecThreads.end(); it++){
(*it)->join();
}
}
};
int main(int argc, char* argv[]){
if(argc != 4){
cout << "Usage : ip port threads" << endl;
return 1;
}
string sIp(argv[1]), sPort(argv[2]);
int iThreads = boost::lexical_cast(argv[3]);
try{
CServer oServer(sIp, sPort, iThreads);
cout << "StartUp Service" << endl;
oServer.Start();
getchar();//按回车键退出程序
oServer.Stop();
cout << "ShutDown Service" << endl;
}
catch(std::exception& e){
cout << "Exception : " << e.what() << endl;
}
return 0;
}
运行效果如下: