源码下载以及安装点击链接https://blog.csdn.net/YoungSusie/article/details/90021742
muduo网络库采取的模式为: one loop per thread + thread pool
0、什么都不用做的EventLoop class
one loop per thread 每个线程只能由一个EventLoop对象,其构造函数会用__thread 类型的变量记住本对象所属的线程ID。
创建了EventLoop 对象的线程是IO线程,其主要功能是运行事件循环loop(),事件循环 必须在IO线程执行。此对象的生命期与线程一样长。
1、学习笔记
- 如何返回线程ID gettid()?
虽然 threads 库提供了pthread_self()
函数返回当前线程的ID,线程ID类型为pthread_t。这里有两个问题:一个是,pthread_t类型无法输出、比较、只在进程内有意义,与操作系统的任务调度之间无法建立有效关联;同时,glibc实现上将pthread_t 用做一个结构体指针,指向动态内存,切该内存会反复使用,只能保证同一时刻同一进程各个线程的ID不同,不能保证同一进程先后多个线程ID不同。因此此函数与返回值类型不适合作为线程的标识符。
可以使用gettid() 系统调用,但是需要注意的是,Glibc并没有提供此接口的声明,此接口实际使用的是系统调用,使用者可以自己创建包裹函数
包裹此函数,并用pid_t 类型作为返回值类型,需要包含头文件#include <sys/types.h> #include <sys/syscall.h>
#include <sys/types.h>
#include <sys/syscall.h>
pid_t gettid()
{
return static_cast<pid_t>(syscall( __NR_gettid));
}
其次还需要注意: 由于本项目的很多地方需要用到这个函数,因此在头文件中声明了该函数,但是不可在头文件中定义此函数,会造成重复定义,即使用了ifndef ,(目前我还不知道为什么)。因此我将该函数的定义放在另外一个gettid.cc文件中。
进程ID 和线程ID 的区别可见连接https://blog.csdn.net/YoungSusie/article/details/91973997
- 前向声明
muduo头文件中使用了向前声明,大大简化了头文件之间的依赖关系。 例如,Poller class, Channel class 都向前声明了EventLoop class,从而避免了包含EventLoop.h 头文件
2、代码
==================================EventLoop.h ====================================
#ifndef _EVENTLOOP_
#define _EVENTLOOP_
#include <boost/noncopyable.hpp>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <iostream>
pid_t gettid(void);
class EventLoop : boost::noncopyable
{
public:
EventLoop();
~EventLoop();
void loop();
/*void assertInLoopThread()
{
if (!isInLoopThread())
{
abortNotInLoopThread();
}
}*/
bool isInLoopThread() const
{
return threadId_ == gettid();
}
private:
// void abortNotInLoopThread;
bool looping_;
pid_t threadId_;
};
#endif
================================== EventLoop.cc =====================================
#include "EventLoop.h"
#include <assert.h>
#include <poll.h>
using namespace std;
__thread EventLoop * t_LoopInThisThread = 0;
EventLoop::EventLoop()
:looping_(false),threadId_(gettid())
{
cout << "EventLoop created" << this << " in thread " << threadId_ << "\n";
t_LoopInThisThread = this;
}
EventLoop::~EventLoop()
{
assert(!looping_);
t_LoopInThisThread = NULL;
}
void EventLoop::loop()
{
assert(!looping_);
looping_ = true;
::poll(NULL,0,5*1000);
looping_ = false;
}
=================================== gettid.cc =======================================
#include "EventLoop.h"
pid_t gettid()
{
return static_cast<pid_t>(syscall( __NR_gettid));
}
=================================== Makefile =======================================
LIB_SRC = EventLoop.cc gettid.cc
BINARIES = test1
all: $(BINARIES)
CXXFLAGS = -O0 -g -Wall -I -pthread
LDFLAGS = -lpthread
$(BINARIES):
g++ $(CXXFLAGS) -o $@ $(LIB_SRC) $(filter %.cc,$^) $(LDFLAGS) // $^--所有的依赖文件 $@--目标文件 $<--第一个依赖文件
clean:
rm -f $(BINARIES) core
test1: test1.cc
本文摘自陈硕老师的linux多线程服务端编程