multiple reactors(35 -1 )
来源:互联网 发布:知远战略与防务研究所 编辑:程序博客网 时间:2024/06/10 03:22
muduo库如何支持多线程
EventLoopThread(IO线程类)
EventLoopThreadPool(IO线程池类)
IO线程池的功能是开启若干个IO线程,并让这些IO线程处于事件循环的状态
下面的这些代码可能和前面给出的源代码有些不一样,阅读的同学请注意了
EventLoopThreadPool头文件
eventloopthreadpool.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H#define MUDUO_NET_EVENTLOOPTHREADPOOL_H#include <muduo/base/Condition.h>#include <muduo/base/Mutex.h>#include <vector>#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/ptr_container/ptr_vector.hpp>namespace muduo{namespace net{class EventLoop;class EventLoopThread;class EventLoopThreadPool : boost::noncopyable{ public: typedef boost::function<void(EventLoop*)> ThreadInitCallback; EventLoopThreadPool(EventLoop* baseLoop); ~EventLoopThreadPool(); void setThreadNum(int numThreads) { numThreads_ = numThreads; } void start(const ThreadInitCallback& cb = ThreadInitCallback()); EventLoop* getNextLoop(); private: EventLoop* baseLoop_; // 与Acceptor所属EventLoop相同 bool started_; /*是否启动*/ int numThreads_; // 线程数 int next_; // 新连接到来,所选择的EventLoop对象下标 boost::ptr_vector<EventLoopThread> threads_; // IO线程列表 std::vector<EventLoop*> loops_; // EventLoop列表};}}#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H
EventLoopThreadPool源文件
eventloopthreadpool.cc
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/EventLoopThreadPool.h>#include <muduo/net/EventLoop.h>#include <muduo/net/EventLoopThread.h>#include <boost/bind.hpp>using namespace muduo;using namespace muduo::net;EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop) : baseLoop_(baseLoop), // 与Acceptor所属EventLoop相同 started_(false), numThreads_(0), next_(0){}EventLoopThreadPool::~EventLoopThreadPool(){ // Don't delete loop, it's stack variable}/*每个线程初始化时的回调函数cb*/void EventLoopThreadPool::start(const ThreadInitCallback& cb){ assert(!started_); baseLoop_->assertInLoopThread(); started_ = true; for (int i = 0; i < numThreads_; ++i) { EventLoopThread* t = new EventLoopThread(cb); threads_.push_back(t); loops_.push_back(t->startLoop()); // 启动EventLoopThread线程,在进入事件循环之前,会调用cb } if (numThreads_ == 0 && cb) { // 只有一个EventLoop,在这个EventLoop进入事件循环之前,调用cb cb(baseLoop_); }}EventLoop* EventLoopThreadPool::getNextLoop(){ baseLoop_->assertInLoopThread(); EventLoop* loop = baseLoop_; // 如果loops_为空,则loop指向baseLoop_ // 如果不为空,按照round-robin(RR,轮叫)的调度方式选择一个EventLoop if (!loops_.empty()) { // round-robin loop = loops_[next_]; ++next_; if (implicit_cast<size_t>(next_) >= loops_.size()) { next_ = 0; } } return loop;}
TcpServer头文件
TcpServer.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_TCPSERVER_H#define MUDUO_NET_TCPSERVER_H#include <muduo/base/Types.h>#include <muduo/net/TcpConnection.h>#include <map>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>namespace muduo{namespace net{class Acceptor;class EventLoop;class EventLoopThreadPool;////// TCP server, supports single-threaded and thread-pool models.////// This is an interface class, so don't expose too much details.class TcpServer : boost::noncopyable{ public: typedef boost::function<void(EventLoop*)> ThreadInitCallback; //TcpServer(EventLoop* loop, const InetAddress& listenAddr); TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& nameArg); ~TcpServer(); // force out-line dtor, for scoped_ptr members. const string& hostport() const { return hostport_; } const string& name() const { return name_; } /// Set the number of threads for handling input. /// /// Always accepts new connection in loop's thread. /// Must be called before @c start /// @param numThreads /// - 0 means all I/O in loop's thread, no thread will created. /// this is the default value. /// - 1 means all I/O in another thread. /// - N means a thread pool with N threads, new connections /// are assigned on a round-robin basis. void setThreadNum(int numThreads); void setThreadInitCallback(const ThreadInitCallback& cb) { threadInitCallback_ = cb; } /// Starts the server if it's not listenning. /// /// It's harmless to call it multiple times. /// Thread safe. void start(); /// Set connection callback. /// Not thread safe. // 设置连接到来或者连接关闭回调函数 void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; } /// Set message callback. /// Not thread safe. // 设置消息到来回调函数 void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; } private: /// Not thread safe, but in loop void newConnection(int sockfd, const InetAddress& peerAddr); /// Thread safe. void removeConnection(const TcpConnectionPtr& conn); /// Not thread safe, but in loop void removeConnectionInLoop(const TcpConnectionPtr& conn); typedef std::map<string, TcpConnectionPtr> ConnectionMap; EventLoop* loop_; // the acceptor loop const string hostport_; // 服务端口 const string name_; // 服务名 boost::scoped_ptr<Acceptor> acceptor_; // avoid revealing Acceptor boost::scoped_ptr<EventLoopThreadPool> threadPool_; //线程池 ConnectionCallback connectionCallback_; MessageCallback messageCallback_; ThreadInitCallback threadInitCallback_; // IO线程池中的线程在进入事件循环前,会回调用此函数 bool started_; // always in loop thread int nextConnId_; // 下一个连接ID ConnectionMap connections_; // 连接列表};}}#endif // MUDUO_NET_TCPSERVER_H
TcpServer源文件
TcpServer.cc
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/TcpServer.h>#include <muduo/base/Logging.h>#include <muduo/net/Acceptor.h>#include <muduo/net/EventLoop.h>#include <muduo/net/EventLoopThreadPool.h>#include <muduo/net/SocketsOps.h>#include <boost/bind.hpp>#include <stdio.h> // snprintfusing namespace muduo;using namespace muduo::net;TcpServer::TcpServer(EventLoop* loop, /*这是main reactor*/ const InetAddress& listenAddr, const string& nameArg) : loop_(CHECK_NOTNULL(loop)), hostport_(listenAddr.toIpPort()), name_(nameArg), acceptor_(new Acceptor(loop, listenAddr)), threadPool_(new EventLoopThreadPool(loop)), /*connectionCallback_(defaultConnectionCallback), messageCallback_(defaultMessageCallback),*/ started_(false), nextConnId_(1){ // Acceptor::handleRead函数中会回调用TcpServer::newConnection // _1对应的是socket文件描述符,_2对应的是对等方的地址(InetAddress) acceptor_->setNewConnectionCallback( boost::bind(&TcpServer::newConnection, this, _1, _2));}TcpServer::~TcpServer(){ loop_->assertInLoopThread(); LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; for (ConnectionMap::iterator it(connections_.begin()); it != connections_.end(); ++it) { TcpConnectionPtr conn = it->second; it->second.reset(); // 释放当前所控制的对象,引用计数减一 conn->getLoop()->runInLoop( boost::bind(&TcpConnection::connectDestroyed, conn)); conn.reset(); // 释放当前所控制的对象,引用计数减一 }}void TcpServer::setThreadNum(int numThreads){ /*numThreads不包含main reactor thread*/ assert(0 <= numThreads); threadPool_->setThreadNum(numThreads);}// 该函数多次调用是无害的// 该函数可以跨线程调用void TcpServer::start(){ if (!started_) { started_ = true; /*启动线程池*/ threadPool_->start(threadInitCallback_); } if (!acceptor_->listenning()) { // get_pointer返回原生指针 loop_->runInLoop( boost::bind(&Acceptor::listen, get_pointer(acceptor_))); }}void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr){ loop_->assertInLoopThread(); // 按照轮叫的方式选择一个EventLoop EventLoop* ioLoop = threadPool_->getNextLoop(); char buf[32]; snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_); ++nextConnId_; string connName = name_ + buf; LOG_INFO << "TcpServer::newConnection [" << name_ << "] - new connection [" << connName << "] from " << peerAddr.toIpPort(); InetAddress localAddr(sockets::getLocalAddr(sockfd)); // FIXME poll with zero timeout to double confirm the new connection // FIXME use make_shared if necessary /*TcpConnectionPtr conn(new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));*/ TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr)); LOG_TRACE << "[1] usecount=" << conn.use_count(); connections_[connName] = conn; LOG_TRACE << "[2] usecount=" << conn.use_count(); conn->setConnectionCallback(connectionCallback_); conn->setMessageCallback(messageCallback_); conn->setCloseCallback( boost::bind(&TcpServer::removeConnection, this, _1)); // conn->connectEstablished(); 这个表示直接在当前线程中调用 ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn)); LOG_TRACE << "[5] usecount=" << conn.use_count();}void TcpServer::removeConnection(const TcpConnectionPtr& conn){ /* loop_->assertInLoopThread(); LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ << "] - connection " << conn->name(); LOG_TRACE << "[8] usecount=" << conn.use_count(); size_t n = connections_.erase(conn->name()); LOG_TRACE << "[9] usecount=" << conn.use_count(); (void)n; assert(n == 1); loop_->queueInLoop( boost::bind(&TcpConnection::connectDestroyed, conn)); LOG_TRACE << "[10] usecount=" << conn.use_count(); */ loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn));}void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn){ loop_->assertInLoopThread(); LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ << "] - connection " << conn->name(); LOG_TRACE << "[8] usecount=" << conn.use_count(); size_t n = connections_.erase(conn->name()); LOG_TRACE << "[9] usecount=" << conn.use_count(); (void)n; assert(n == 1); EventLoop* ioLoop = conn->getLoop(); ioLoop->queueInLoop( boost::bind(&TcpConnection::connectDestroyed, conn)); //loop_->queueInLoop( // boost::bind(&TcpConnection::connectDestroyed, conn)); LOG_TRACE << "[10] usecount=" << conn.use_count();}
测试程序
#include <muduo/net/TcpServer.h>#include <muduo/net/EventLoop.h>#include <muduo/net/InetAddress.h>#include <boost/bind.hpp>#include <stdio.h>using namespace muduo;using namespace muduo::net;class TestServer{ public: TestServer(EventLoop* loop, const InetAddress& listenAddr, int numThreads) : loop_(loop), server_(loop, listenAddr, "TestServer"), numThreads_(numThreads) { server_.setConnectionCallback( boost::bind(&TestServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&TestServer::onMessage, this, _1, _2, _3)); server_.setThreadNum(numThreads); } void start() { server_.start(); } private: void onConnection(const TcpConnectionPtr& conn) { if (conn->connected()) { printf("onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toIpPort().c_str()); } else { printf("onConnection(): connection [%s] is down\n", conn->name().c_str()); } } void onMessage(const TcpConnectionPtr& conn, const char* data, ssize_t len) { printf("onMessage(): received %zd bytes from connection [%s]\n", len, conn->name().c_str()); } EventLoop* loop_; TcpServer server_; int numThreads_;};int main(){ printf("main(): pid = %d\n", getpid()); InetAddress listenAddr(8888); EventLoop loop; TestServer server(&loop, listenAddr,4); server.start(); loop.loop();}
- multiple reactors(35 -1 )
- multiple reactors(35 -1 )
- 8、multiple reactors(能适应更大的突发I/O) 多个事件循环
- 9、multiple reactors + thread pool(one loop per thread + threadpool)(突发I/O与密集计算)
- multiple reactors + thread pool(one loop per thread + threadpool)(突发I/O与密集计算)
- Codechef Nuclear Reactors 题解
- 4-1 Multiple Feature
- Multiple
- SSD3 Multiple-Choice Quiz 1
- ssd3 Multiple-Choice Quiz 1
- linear regression(1)-multiple features
- Adobe Reader 7.0.1 update - multiple languages
- Multiple Language Syntax Highlighting, Part 1: JScript
- Multiple Language Syntax Highlighting, Part 1: JScript
- Smallest multiple 求1-20的最小公倍数
- 4 - 1 - Multiple Features (8 min)
- Dump分析模式1: Multiple Exceptions(多线程异常)
- error: "libevent-1.1a-3.2.1" specifies multiple packages
- 第11周项目5-个人应缴税款和税后收入
- nfs:server is not responding,still trying问题
- 测试String对象的创建
- 快递员工作-贪心-区间
- ACM-数论之吃糖果——hdu1205
- multiple reactors(35 -1 )
- Linux 线程锁详解
- Android文件存放
- 如何在LINUX下启动ORACLE
- 产生一个50X2的矩阵(二维数组),每个元素是0-10的随机数
- uva 1160 - X-Plosives(并查集)
- NYOJ-132-最长回文子串-2013年08月12日21:49:03
- Excel中计算个人所得税的公式
- 文件描述符的分析(35-2)