muduo
クラスEventLoopThreadPool
のコンストラクターでは、メンバーはnumThreads_
0に設定されます。これは、マスタースレーブReactorモードがデフォルトでオンになっていないこと、つまりシングルReactorモードであることを意味します。
シングルReactor
モードでReactor
は、新しい接続の到着とソケットの読み取りと書き込みを監視します。
呼び出しの前に通過し、呼び出しvoid TcpServer::start()
ますEventLoopThreadPool::setThreadNum()
。マスタースレーブリアクターモードをオンにすることができます。
クラスTcpServe
rの構造は次のとおりです。
class TcpServer : noncopyable
{
public:
...
private:
EventLoop* loop_; // the acceptor loop
...
std::shared_ptr<EventLoopThreadPool> threadPool_;
...
};
TcpServer
構築時に、構築されたEventLoopオブジェクトが渡され、メインスレッドloop_
でloop_
実行されるメンバーに割り当てられます。
それ个EventLoop
がメインのReactorであり、新しい接続要求の監視のみを担当すると言います。
TcpServer::TcpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& nameArg,
Option option)
: loop_(CHECK_NOTNULL(loop)), // 外部直接传入
ipPort_(listenAddr.toIpPort()),
name_(nameArg),
acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), // 将loop_作为主reactor使用
threadPool_(new EventLoopThreadPool(loop, name_)),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(
std::bind(&TcpServer::newConnection, this, _1, _2));
}
サーバーが起動すると、サーバーが呼び出されTcpServer::start()
、EventLoopThreadPool::start(const ThreadInitCallback& cb)
子スレッドを初期化して実行し、TcpServer::threadPool_
これらの子スレッドで実行されてEventLoop
いる無限イベントループに保存するために再度呼び出されます。これらの実行EventLoopThread
は、ReactorからのものとEventLoop
呼ばれます。
void TcpServer::start()
{
if (started_.getAndSet(1) == 0)
{
threadPool_->start(threadInitCallback_);
assert(!acceptor_->listenning());
loop_->runInLoop(
std::bind(&Acceptor::listen, get_pointer(acceptor_)));
}
}
void EventLoopThreadPool::start(const ThreadInitCallback& cb)
{
assert(!started_);
baseLoop_->assertInLoopThread();
started_ = true;
for (int i = 0; i < numThreads_; ++i)
{
char buf[name_.size() + 32];
snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i);
EventLoopThread* t = new EventLoopThread(cb, buf);
threads_.push_back(std::unique_ptr<EventLoopThread>(t));
loops_.push_back(t->startLoop());
}
if (numThreads_ == 0 && cb)
{
cb(baseLoop_);
}
}
接続されたソケットの場合、それらのイベントの監視はスレーブReactor、つまり子スレッドで実行されているEventLoopの責任です。
ときスレーブ原子炉が必要とされ、それが呼び出される必要がありますEventLoopThreadPool->getNextLoop()
。
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
loop_->assertInLoopThread();
EventLoop* ioLoop = threadPool_->getNextLoop(); // 这里获取一个从reactor
char buf[64];
snprintf(buf, sizeof buf, "-%s#%d", ipPort_.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(ioLoop,
connName,
sockfd,
localAddr,
peerAddr));
...;
}
EventLoop* EventLoopThreadPool::getNextLoop()
{
baseLoop_->assertInLoopThread();
assert(started_);
EventLoop* loop = baseLoop_;
if (!loops_.empty())
{
// round-robin
loop = loops_[next_];
++next_;
if (implicit_cast<size_t>(next_) >= loops_.size())
{
next_ = 0;
}
}
return loop;
}