1. IOThread
只有io thread才会使用libevent,如使用event_base_loop等函数。上层task要添加event,也得下到io thread的event_base上。
io thread 0的listenSocket 为有效值,只有它注册了listenHandler,所以也只有thread 0会侦听。
TNonblockingIOThread::run()
if (listenSocket_ >= 0) {
// Register the server event
event_set(&serverEvent_,
listenSocket_,
EV_READ | EV_PERSIST,
TNonblockingIOThread::listenHandler,
server_);
static void listenHandler(evutil_socket_t fd, short which, void* v) {
((TNonblockingServer*)v)->handleEvent(fd, which);
}
io thread可以有很多个,缺省只有一个,可以通过setNumIOThreads()来设置。在thrift-0.9里头,io thread 0也是进程的主线程。如果只有一个io thread(即io thread 0)则此io thread 负责所有io
if (clientConnection->getIOThreadNumber() == 0) {
clientConnection->transition();
} else {
clientConnection->notifyIOThread();
}
handleEvent()
-->createConnection()
io thread 0接收一个连接,创建一个connection,同时分配某个io thread给这个connection。io thread主要负责io(socket的read和write),具体的task(用来处理Ttransport收上来的数据,做计算用)用thread manager里头的thread来完成。
除了listen socket外,其他connection(对应到一个io thread)都注册 TConnection::eventHandler和TNonblockingIOThread::notifyHandler,注册到iothread的event_base上头。
event_set(&event_, tSocket_->getSocketFD(), eventFlags_,
TConnection::eventHandler, this); eventFlags被设成read/write来控制io
TConnection::eventHandler()
->TConnection::workSocket()
->TConnection::transition()
->TNonblockingServer::addTask(TNonblockingServer::TConnection::Task)
->ThreadManager::add()
2. Worker Thread
worker是thread manager创建的线程实体,即用于计算的thread pool。worker的多少可以通过newSimpleThreadManager的参数count来指定。
worker::run()
-->ThreadManager::Task::run()
-->TNonblockingServer::TConnection::Task::run() -->processor_->process(input_, output_, connectionContext_)
worker线程的挂起点,由于有挂起点,所以thrift server一般不会high cpu.
#0 0x00002b26d3bcd326 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1 0x000000000058edb5 in apache::thrift::concurrency::Monitor::wait (this=<value optimized out>, timeout=0) at src/concurrency/Monitor.cpp:80
#2 0x0000000000583b0e in apache::thrift::concurrency::ThreadManager::Worker::run (this=0x7e0580) at src/concurrency/ThreadManager.cpp:279
总共看下来,整个进程就是N个io thread加上N个worker thread。
创建thread的地方查询newThread()被调用的地方就行,对于事件的主要执行体,查找event_set就行,non-blocking server体现在对所有的socket都设为non-block,查询O_NONBLOCK。想查看读事件在什么时机触发,查询EV_READ。