把原书第8章的例子《设计Reactor——如何从头开始编写非阻塞网络库》
地址: https://github.com/chenshuo/recipes/tree/master/reactor
用 c++11 搞了一遍,并且简化到全部代码放在一个文件中,方便察看。
步骤0:什么都不做的 event loop 事件循环
EventLoop, assertInLoopThread()
这个步骤里,作者只想强调如何保证每个线程中只能创建一个EventLoop对象,而且如何保证此对象中的loop函数只能在本线程中被调用。
test1: poll 5秒钟,创建两个线程,每个线程都有一个 EventLoop 对象
#include
#include
#include
#include
#include
class EventLoop;
__thread EventLoop* t_loopInThisThread = nullptr;
class EventLoop
{
public:
EventLoop() : looping_(false), threadId_(std::this_thread::get_id())
{
std::cout << "EventLoop created " << this << " in thread " << threadId_ << std::endl;
if (t_loopInThisThread) {
std::cout << "Another EventLoop " << t_loopInThisThread << " exists in this thread " << threadId_ << std::endl;
abort();
} else {
t_loopInThisThread = this;
}
}
~EventLoop()
{
assert(!looping_);
t_loopInThisThread = nullptr;
}
static EventLoop* getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
void loop()
{
assert(!looping_);
assertInLoopThread();
looping_ = true;
::poll(NULL, 0, 5*1000);
std::cout << "EventLoop " << this << " stop looping in thread " << std::this_thread::get_id() << std::endl;
looping_ = false;
}
void assertInLoopThread()
{
if (!isInLoopThread()) {
abortNotInLoopThread();
}
}
bool isInLoopThread() const
{
return threadId_ == std::this_thread::get_id();
}
private:
EventLoop(const EventLoop&) = delete;
EventLoop& operator=(const EventLoop&) = delete;
void abortNotInLoopThread()
{
std::cout << "EventLoop::abortNotInLoopThread - EventLoop " << this
<< " was created in threadId_ = " << threadId_
<< ", current thread id = " << std::this_thread::get_id() << std::endl;
abort();
}
bool looping_;
const std::thread::id threadId_;
};
void threadFunc()
{
std::cout << "threadFunc(): pid = " << getpid() << ", tid = " << std::this_thread::get_id() << std::endl;
EventLoop loop;
loop.loop();
}
int main()
{
std::cout << "main(): pid = " << getpid() << ", tid = " << std::this_thread::get_id() << std::endl;
EventLoop loop;
std::thread t(threadFunc);
loop.loop();
t.join();
}
运行结果
test2: 当从其它线程访问EventLoop时调用abort()退出
#include
#include
#include
#include
#include
class EventLoop;
__thread EventLoop* t_loopInThisThread = nullptr;
class EventLoop
{
public:
EventLoop() : looping_(false), threadId_(std::this_thread::get_id())
{
std::cout << "EventLoop created " << this << " in thread " << threadId_ << std::endl;
if (t_loopInThisThread) {
std::cout << "Another EventLoop " << t_loopInThisThread << " exists in this thread " << threadId_ << std::endl;
abort();
} else {
t_loopInThisThread = this;
}
}
~EventLoop()
{
assert(!looping_);
t_loopInThisThread = nullptr;
}
static EventLoop* getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
void loop()
{
assert(!looping_);
assertInLoopThread();
looping_ = true;
::poll(NULL, 0, 5*1000);
std::cout << "EventLoop " << this << " stop looping in thread " << std::this_thread::get_id() << std::endl;
looping_ = false;
}
void assertInLoopThread()
{
if (!isInLoopThread()) {
abortNotInLoopThread();
}
}
bool isInLoopThread() const
{
return threadId_ == std::this_thread::get_id();
}
private:
EventLoop(const EventLoop&) = delete;
EventLoop& operator=(const EventLoop&) = delete;
void abortNotInLoopThread()
{
std::cout << "EventLoop::abortNotInLoopThread - EventLoop " << this
<< " was created in threadId_ = " << threadId_
<< ", current thread id = " << std::this_thread::get_id() << std::endl;
abort();
}
bool looping_;
const std::thread::id threadId_;
};
EventLoop* g_loop;
void threadFunc()
{
g_loop->loop();
}
int main()
{
EventLoop loop;
g_loop = &loop;
std::thread t(threadFunc);
t.join();
}
运行结果
步骤1:Reactor原型
Channel, Poller, updateChannel()
test1: 永不退出的poll, 创建2个线程,每个线程中都有一个EventLoop
本例子中,EventLoop对象只创建了一个 Poller 对象(在初始化列表中 new 的)存放在智能指针 poller_ 内,还没有涉及 Channel 的对象操作。所以只是对空的 pollfds_ 进行 poll 系统调用,实际上就是什么描述符都没有观察,当然也不会poll到任何事件。
#include
#include
#include
#include
#include
#include
#include
#include
#include
运行结果
test2: 当从其它线程访问EventLoop时调用abort()退出
#include
#include
#include
#include
#include
#include
#include
#include
#include
运行结果
test3: poll一个会在5秒钟超时的timerfd描述符
#include
#include
#include
#include
#include
#include
#include
#include
#include
运行结果