文章目录
本来没想看这一块, 但是看TCPServer class
的时候里面用到了, 所以先总结一下这两个类的封装
功能
这三个类并不难理解, 没有很复杂的逻辑, 是对一些操作的简单封装
前面说了只要创建运行了EventLoop
的线程就是 IO 线程, EventLoopThread
是对 IO 线程的封装, EventLoopThreadPool
是 IO 线程池, 负责创建和分发 IO 线程,
Thread class
介绍EventLoopThread
之前, 先介绍一下Thread class
, 在EventLoopThread
有一个Thread
类的对象
Thread.h
#ifndef MUDUO_BASE_THREAD_H
#define MUDUO_BASE_THREAD_H
#include <muduo/base/Atomic.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Types.h>
#include <functional>
#include <memory>
#include <pthread.h>
namespace muduo
{
class Thread : noncopyable
{
public:
typedef std::function<void ()> ThreadFunc;
explicit Thread(ThreadFunc, const string& name = string()); //显示构造函数
// FIXME: make it movable in C++11
~Thread();
void start();
int join(); // return pthread_join()
bool started() const { return started_; }
// pthread_t pthreadId() const { return pthreadId_; }
pid_t tid() const { return tid_; }
const string& name() const { return name_; }
static int numCreated() { return numCreated_.get(); }
private:
void setDefaultName();
bool started_;
bool joined_;
pthread_t pthreadId_;
pid_t tid_;
ThreadFunc func_;
string name_;
CountDownLatch latch_;
static AtomicInt32 numCreated_;
};
} // namespace muduo
#endif // MUDUO_BASE_THREAD_H
Thread.cc
#include <muduo/base/Thread.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Exception.h>
#include <muduo/base/Logging.h>
#include <type_traits>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/unistd.h>
namespace muduo
{
namespace detail
{
pid_t gettid()
{
return static_cast<pid_t>(::syscall(SYS_gettid));
}
void afterFork()
{
muduo::CurrentThread::t_cachedTid = 0;
muduo::CurrentThread::t_threadName = "main";
CurrentThread::tid();
// no need to call pthread_atfork(NULL, NULL, &afterFork);
}
class ThreadNameInitializer
{
public:
ThreadNameInitializer()
{
muduo::CurrentThread::t_threadName = "main";
CurrentThread::tid();
pthread_atfork(NULL, NULL, &afterFork);
}
};
ThreadNameInitializer init;
struct ThreadData
{
typedef muduo::Thread::ThreadFunc ThreadFunc;
ThreadFunc func_;
string name_;
pid_t* tid_;
CountDownLatch* latch_;
ThreadData(ThreadFunc func,
const string& name,
pid_t* tid,
CountDownLatch* latch)
: func_(std::move(func)),
name_(name),
tid_(tid),
latch_(latch)
{ }
void runInThread()
{
*tid_ = muduo::CurrentThread::tid();
tid_ = NULL;
latch_->countDown();
latch_ = NULL;
muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str();
::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName);
try
{
func_(); //执行指定的线程函数,即 EventLoopThread::threadFunc
muduo::CurrentThread::t_threadName = "finished";
}
catch (const Exception& ex)
{
muduo::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
fprintf(stderr, "reason: %s\n", ex.what());
fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
abort();
}
catch (const std::exception& ex)
{
muduo::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
fprintf(stderr, "reason: %s\n", ex.what());
abort();
}
catch (...)
{
muduo::CurrentThread::t_threadName = "crashed";
fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
throw; // rethrow
}
}
};
void* startThread(void* obj)
{
ThreadData* data = static_cast<ThreadData*>(obj);
data->runInThread();
delete data;
return NULL;
}
} // namespace detail
void CurrentThread::cacheTid()
{
if (t_cachedTid == 0)
{
t_cachedTid = detail::gettid();
t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
}
}
bool CurrentThread::isMainThread()
{
return tid() == ::getpid();
}
void CurrentThread::sleepUsec(int64_t usec)
{
struct timespec ts = { 0, 0 };
ts.tv_sec = static_cast<time_t>(usec / Timestamp::kMicroSecondsPerSecond);
ts.tv_nsec = static_cast<long>(usec % Timestamp::kMicroSecondsPerSecond * 1000);
::nanosleep(&ts, NULL);
}
AtomicInt32 Thread::numCreated_;
Thread::Thread(ThreadFunc func, const string& n)
: started_(false),
joined_(false),
pthreadId_(0),
tid_(0),
func_(std::move(func)),
name_(n),
latch_(1)
{
setDefaultName();
}
Thread::~Thread()
{
if (started_ && !joined_)
{
pthread_detach(pthreadId_);
}
}
void Thread::setDefaultName()
{
int num = numCreated_.incrementAndGet();
if (name_.empty())
{
char buf[32];
snprintf(buf, sizeof buf, "Thread%d", num);
name_ = buf;
}
}
//EventLoopThread::startLoop会调用该函数( thread_::start() )
//func_变量在EventLoopThread的构造函数中被指定为EventLoopThread::threadFunc
void Thread::start()
{
assert(!started_);
started_ = true;
// FIXME: move(func_)
//创建一个ThreadData类对象,其中保存有被指定的线程函数EventLoopThread::threadFunc
//再将该对象传入创建的线程中
//在该线程中执行被指定的线程函数
detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
{
started_ = false;
delete data; // or no delete?
LOG_SYSFATAL << "Failed in pthread_create";
}
else
{
latch_.wait();
assert(tid_ > 0);
}
}
int Thread::join()
{
assert(started_);
assert(!joined_);
joined_ = true;
return pthread_join(pthreadId_, NULL);
}
} // namespace muduo
在EventLoopThread::startLoop
中会调用Thread::start()
, 并执行在EventLoopThread
中指定的线程函数
EventLoopThread
IO 线程不一定是主线程, 我们可以在任意一个线程中创建并运行EventLoopThread
, 一个程序也可以拥有不止一个 IO 线程, EventLoopThread
会启动自己的线程, 并运行EventLoop::loop
主线程创建EventLoopThread
对象, 调用EventLoopThread::startLoop()
创建 IO 线程, 该函数会等待 IO 线程创建完成才返回
EventLoopThread.h
#ifndef MUDUO_NET_EVENTLOOPTHREAD_H
#define MUDUO_NET_EVENTLOOPTHREAD_H
#include <muduo/base/Condition.h>
#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
namespace muduo
{
namespace net
{
class EventLoop;
class EventLoopThread : noncopyable
{
public:
typedef std::function<void(EventLoop*)> ThreadInitCallback;
EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(),
const string& name = string());
~EventLoopThread();
EventLoop* startLoop(); //启动线程,该线程成为IO线程
private:
void threadFunc(); //线程函数
EventLoop* loop_ GUARDED_BY(mutex_); //指向一个EventLoop对象
bool exiting_;
Thread thread_; //Thread是对线程的一些操作进行封装
MutexLock mutex_;
Condition cond_ GUARDED_BY(mutex_);
ThreadInitCallback callback_;
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_EVENTLOOPTHREAD_H
EventLoopThread.cc
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;
EventLoopThread::EventLoopThread(const ThreadInitCallback& cb,
const string& name)
: loop_(NULL),
exiting_(false),
//将线程函数绑定为threadFunc
thread_(std::bind(&EventLoopThread::threadFunc, this), name),
mutex_(),
cond_(mutex_),
callback_(cb)
{
}
EventLoopThread::~EventLoopThread()
{
exiting_ = true;
if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_.
{
// still a tiny chance to call destructed object, if threadFunc exits just now.
// but when EventLoopThread destructs, usually programming is exiting anyway.
loop_->quit();
thread_.join();
}
}
EventLoop* EventLoopThread::startLoop()
{
assert(!thread_.started());
//在Thread::start中执行指定的线程函数,即EventLoopThread::threadFunc,
//创建EventLoop对象
thread_.start();
EventLoop* loop = NULL;
{
MutexLockGuard lock(mutex_);
while (loop_ == NULL)
{
//需要等待直到指定的EventLoop对象被创建
cond_.wait();
}
loop = loop_;
}
//返回一个指向栈上对象的EventLoop指针
return loop;
}
void EventLoopThread::threadFunc()
{
EventLoop loop;
if (callback_)
{
//该回调函数callback_由TcpServer::setThreadInitCallback()指定
///需要由用户手动指定
//没有就不执行
callback_(&loop);
}
{
MutexLockGuard lock(mutex_);
//loop_指向一个栈上的局部变量,因为该函数退出,意味着线程结束了,那么EventLoopThread对象也就没有存在价值了
loop_ = &loop;
//创建好了,发送通知
cond_.notify();
}
//在这里循环,知道EventLoopThread析构,然后也不会再用loop_访问EventLoop了
loop.loop();
//assert(exiting_);
MutexLockGuard lock(mutex_);
loop_ = NULL;
}
EventLoop* EventLoopThread::startLoop()
返回的是创建的EventLoop
对象 (位于栈上) 的指针, 这样我们在主线程调用该函数拿到的就是指向创建的 IO 线程的指针,然后就向上一片博客中介绍的那样, 可以调用EventLoop::runInLoop
来执行任务
EventLoopThreadPool
IO线程池创建分发 IO 线程
EventLoopThreadPool.h
#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H
#define MUDUO_NET_EVENTLOOPTHREADPOOL_H
#include <muduo/base/noncopyable.h>
#include <muduo/base/Types.h>
#include <functional>
#include <memory>
#include <vector>
namespace muduo
{
namespace net
{
class EventLoop;
class EventLoopThread;
class EventLoopThreadPool : noncopyable
{
public:
typedef std::function<void(EventLoop*)> ThreadInitCallback;
EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg);
~EventLoopThreadPool();
//设置线程池线程数目
void setThreadNum(int numThreads) { numThreads_ = numThreads; }
void start(const ThreadInitCallback& cb = ThreadInitCallback());
// valid after calling start()
/// round-robin
EventLoop* getNextLoop();
/// with the same hash code, it will always return the same EventLoop
EventLoop* getLoopForHash(size_t hashCode);
std::vector<EventLoop*> getAllLoops();
bool started() const
{ return started_; }
const string& name() const
{ return name_; }
private:
EventLoop* baseLoop_;
string name_;
bool started_;
int numThreads_; //线程数
int next_; //有新连接到来时需要选择的新的EventLoop对象的下标
std::vector<std::unique_ptr<EventLoopThread>> threads_; //IO线程列表
std::vector<EventLoop*> loops_;
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H
EventLoopThreadPool.cc
主要是其start
函数
#include <muduo/net/EventLoopThreadPool.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/EventLoopThread.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg)
: baseLoop_(baseLoop),
name_(nameArg),
started_(false),
numThreads_(0),
next_(0)
{
}
EventLoopThreadPool::~EventLoopThreadPool()
{
// Don't delete loop, it's stack variable
}
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);
//由TCPServer::start中调用该函数时传入cb
//创建一个IO线程并运行
EventLoopThread* t = new EventLoopThread(cb, buf);
//压入IO线程列表
threads_.push_back(std::unique_ptr<EventLoopThread>(t));
//t->startLoop函数返回一个栈上的EventLoop对象指针
loops_.push_back(t->startLoop());
}
//只有一个EventLoop,在其进入循环之前,调用cb
if (numThreads_ == 0 && cb)
{
cb(baseLoop_);
}
}
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;
}
EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode)
{
baseLoop_->assertInLoopThread();
EventLoop* loop = baseLoop_;
if (!loops_.empty())
{
loop = loops_[hashCode % loops_.size()];
}
return loop;
}
std::vector<EventLoop*> EventLoopThreadPool::getAllLoops()
{
baseLoop_->assertInLoopThread();
assert(started_);
if (loops_.empty())
{
return std::vector<EventLoop*>(1, baseLoop_);
}
else
{
return loops_;
}
}
上面介绍过了, EventLoopThread
创建号 IO 线程后直接执行loop
函数进入循环, EventLoopThreadPool
创建 IO 线程, 保存他们的指针