文章目录

  • 全流程实现博客链接
  • 前引
  • (五)---- 浅沿芳草鲜花小路静心踱步 拨云见雾终见多线程ThreadPool
    • 1、理清头绪 直通主路 抓住重点
    • 2、罗列代码 一回生二回熟 再次起航
      • 1、echo.h
      • 1、echo.cc
      • 2、tcpserver.h
      • 2、tcpserver.cc
      • 3、acceptor.h
      • 3、acceptor.cc
      • 4、channel.h
      • 4、channel.cc
      • 5、tcpconnectionptr.h
      • 5、tcpconnectionptr.cc
      • 6、eventloop.h
      • 6、eventloop.cc
      • 7、epoller.h
      • 7、epoller.cc
      • 8、eventloopthreadpool.h(新增文件)
      • 8、eventloopthreadpool.cc(新增文件)
      • 9、eventloopthread.h(新增文件)
      • 9、eventloopthread.cc(新增文件)
      • 10、thread.h(新增文件)
      • 10、thread.cc(新增文件)
    • 3、其他组件(Address、Callback、Mutex、Condition、makefile等等)
      • 1、address.h
      • 2、callback.h
      • 3、mutex.h(新增文件)
      • 4、condition.h(新增文件)
      • 5、latch.h(新增文件)
      • 6、makefile(注意链接 -lpthread)
    • 4、tiny_muduo echo(One Loop Per Thread + Thread Pool 默认8线程) test
  • 结束语

全流程实现博客链接


从零开始自制实现C++ High-Performance WebServer 全流程记录(基于muduo网络库)


前引


哎 刚刚真的太难绷了 家人们
之前同班同学在想 如何在c++课堂上的随机30秒问答题拿高分 把综测弄高一点
就找上了我 让我有题看到了就来做做
本着好心 想着能帮兄弟一把是一把 反正也无所谓 自然也就答应了下来
如果有题目来了 就可以发消息给我 我马上看了来做 30秒钟 我还需要马上打开手机 马上点进在线课堂 然后浏览题目 选完后 跟同学发消息 什么答案
结果刚刚发生了一件事情太难让我绷住了
一道理论题 复制构造函数的形式是什么
四个选项 看到题目 我在脑海中疯狂搜索 什么是复制构造函数 我怎么不知道 一点印象都没有 然后就说了一个A 结果答案是C

然后对此 我那位好兄弟 就对我进行了一番点评 部分截图如下 实在是让我羞愧难当 狡辩都没办法狡辩 在回复消息的时候 我确实真的还不知道什么是复制构造函数… 最恐怖的是 我脑子里面真的一点这个函数的印象都没有


于是刚刚我实在找不到借口了 我的同学还说 全班的这道题目都对了 就我一个人错了 天啦。。 我还在想 怎么用c++实现一个线程安全的tiny_muduo 由此来实现一个高性能的多线程服务器 结果被锐评了一番

我想了想 是不是自己基础不扎实 不过关呢 但是说真的 再怎么不过关 也不至于我不知道这个概念吧 复制构造函数究竟是什么 我真的不知道 然后我就去百度了一下 结果如下


哎 竟然是我天天都在写的 熟悉的不能再熟悉的 拷贝构造函数 。。。 我没想到 拷贝构造函数的别名alias竟然是 复制构造函数… 可能是业内拷贝构造函数说的太多了 而且我对此印象太深刻了 但是我是真的不知道有复制构造函数这种说法

心中千万个草泥马飞过去 很无奈 哈哈
这件事也就且当一门趣事给大家分享一下 也就是刚刚发生的
再附一张我和那位好兄弟之间的聊天截图吧 希望以后不要再在我身上发生这样的囧事了 哈哈


(五)---- 浅沿芳草鲜花小路静心踱步 拨云见雾终见多线程ThreadPool


我又取了这样 哈哈 很有意境的标题
《浅沿芳草鲜花小路静心踱步 拨云见雾终见多线程ThreadPool》 读完我甚至都想来加一句 Skr~ 静心踱步 ThreadPool 还押韵了 哈哈

尽管呢 现在我还没有拿起我的小白纸 去研究EventLoopThreadPool 但是呢 哈哈 就是想来写一些博客 没别的多的想法


最上面的那段话是我第二天来编辑的 按照以往的性格 我应该就把上面的那段话给删掉了 但现在想了想也觉得还是很搞笑 算了 就留着吧 哈哈

刚刚又忍不住去看了看书 每当看了几页这本《linux多线程服务端编程》 总觉得自己啥都不会 … 而且会被马上打乱现在已经有的头绪
其实现在的建议就是 多看源码 源码为主 书籍为辅 先不管三七二十一 把源码看懂 很多地方摸棱两可的也无所谓 我觉得真的到看书的那一步 是真的等差不多把一个有很多地方有缺陷 有疑惑的服务器做出来了 再去在书中找答案 哈哈 想到作为一名初学者 看到这样的书籍的时候 很难不会觉得头脑昏胀 头晕目眩


此时如果各位读者看到这段话 基本上 一个有着到差不差的框架的muduo了 哈哈 不容易啊 但是不好的消息是什么 身体抱恙了 可能是这段时间温差太大了 或者是自己衣服穿的稍微有点少 又或者是 自己没怎么休息好 反正就身体不是那么好 然后昨天重感冒了 今天晚上待会把博客发了就回寝室休息去了 各位在学习生活的日子里面 无论如何还是把身体放在第一位吧


1、理清头绪 直通主路 抓住重点


到了ThreadPool部分了 其实也就是分析一下 相较于之前的单线程的Reactor需要添加什么文件

1、EventLoopThreadPool 总的线程池 TcpServer连接新连接 交互就是与总的线程池相沟通
2、EventLoopThread 封装线程 一些与线程相关的成员 以及做到EventLoopThreadPool 与Thread 信息传递的一些作用
3、Thread 最基类的成员 线程类 被EventLoopThread包装
4、MutexLock Condition Latch 互斥锁、条件变量、屏障 前两个就不介绍了 屏障主要是 同步父子进程间的执行进度(互斥锁、条件变量的封装类)

其实主要添加的也就这么几个文件 然后再去添加一些EventLoop TcpServer的函数 这个大概我也就花了不到一天的时间也就完成了工作 这段时间人身体不是很好 效率比较低 一天左右也就完成了

理清了之后 然后我又去看了遍源码 大概又去理了一下思路后 又独自去写代码了
这次进度相较于第一次 就快了相当的多了 后面代码调试也是没调一会就好了 发现自己条件变量 、 互斥量还不怎么会用 对于一些线程间通信原语还不太熟 又去补了补知识 查了查博客 看了看书 再加上这边自己调试 自然而然也就好了

然后这里基本上 也就采用了RAII 很多细节的地方确实想不到 想了半天还是不知道怎么实现的时候 只能重新返回去看源码 然后再返回来写
调试的过程 没有用之前做CSAPP所用的gdb调试法 还是用的和之前做操作系统的时候 最简单 最熟练的调试方法 printf + 不断地修改 make 运行 然后看一下程序卡在了哪里

基本上也就是这些了 对于之后怎么处理 肯定是 在重新读几遍这本书 里面很多细节 比如 线程为什么有冲突 怎么合理的解决 对了 这次没有处理内存 所以里面是涉及大量的内存泄露的 基本上析构函数都是没有写的

后面的基本上也就是在这个基础上 不断地修改 不断地完善 然后把最终的一个健壮的网络库写出来 其实也就是我写这些博客的最终目的啦

这一篇的代码没有处理内存 只管分配 不管释放 基本运行正确也就算成功了 好了 先写到这里

这里相较于第一个版本 顺带再把有一个类名 之前取错了 之后打算再改了 TcpConnectionPtr改成TcpConnection 在这里我就不改了 感冒了不是很舒服 现在也没有改 想早点回去休息了 改的话 又要去改各种头文件 还有makefile也要改 估计改下来又要花一点时间 这个任务就留在下篇吧


2、罗列代码 一回生二回熟 再次起航


这次默认是8线程的 thread pool + one loop per thread
相较于之前也算是阶段性的胜利了 哈哈


1、echo.h


#ifndef TINY_MUDUO_ECHO_H_
#define TINY_MUDUO_ECHO_H_#include <stdio.h>#include <string>#include "tcpserver.h"
#include "tcpconnectionptr.h"static const int thread_nums = 8;namespace tiny_muduo {class Address;class EventLoop;}class EchoServer {public:EchoServer(tiny_muduo::EventLoop* loop, const tiny_muduo::Address& listen_addr);~EchoServer() {}void Start() {server_.Start();}void ConnectionCallback(tiny_muduo::TcpConnectionPtr* connection_ptr) {printf("echo_server has a new connection \n");  }void MessageCallback(tiny_muduo::TcpConnectionPtr* connection_ptr) {std::string message(connection_ptr->Get());printf("echo_server get message \n");connection_ptr->Send(message);}private:tiny_muduo::EventLoop* loop_;tiny_muduo::TcpServer server_;
};
#endif

1、echo.cc


#include "echo.h"#include "tcpserver.h"EchoServer::EchoServer(tiny_muduo::EventLoop* loop, const tiny_muduo::Address& listen_addr): loop_(loop),server_(loop, listen_addr) {server_.SetConnectionCallback(std::bind(&EchoServer::ConnectionCallback, this, _1));server_.SetMessageCallback(std::bind(&EchoServer::MessageCallback, this, _1));server_.SetThreadNums(thread_nums);
}

2、tcpserver.h


#ifndef TINY_MUDUO_TCPSERVER_H_
#define TINY_MUDUO_TCPSERVER_H_#include "callback.h"
#include "eventloop.h"
#include "acceptor.h"
#include "eventloopthreadpool.h"namespace tiny_muduo {class Address;class TcpServer {public:TcpServer(EventLoop* loop, const Address& address);~TcpServer();void Start() {threads_->StartLoop();loop_->RunOneFunc(std::bind(&Acceptor::Listen, acceptor_));}void SetConnectionCallback(const ConnectionCallback& callback) { connection_callback_ = callback;}void SetMessageCallback(const MessageCallback& callback) {message_callback_ = callback;}void SetThreadNums(int thread_nums) {threads_->SetThreadNums(thread_nums);    }void NewConnection(int connfd);private:EventLoop* loop_;EventLoopThreadPool* threads_;Acceptor* acceptor_;ConnectionCallback connection_callback_;MessageCallback message_callback_;
};}// namespace tiny_muduo
#endif

2、tcpserver.cc


#include "tcpserver.h"#include "eventloopthreadpool.h"
#include "acceptor.h"
#include "tcpconnectionptr.h"using namespace tiny_muduo;TcpServer::TcpServer(EventLoop* loop, const Address& address): loop_(loop),threads_(new EventLoopThreadPool(loop_)),acceptor_(new Acceptor(loop, address)) {acceptor_->SetNewConnectionCallback(std::bind(&TcpServer::NewConnection, this, _1));
}TcpServer::~TcpServer() {delete threads_;delete acceptor_;
}void TcpServer::NewConnection(int connfd) {EventLoop* loop = threads_->NextLoop(); printf("TcpServer NewConnection Arrive Tid:%ld Manage\n", loop->DebugShowTid());TcpConnectionPtr* ptr = new TcpConnectionPtr(loop, connfd);ptr->SetConnectionCallback(connection_callback_);ptr->SetMessageCallback(message_callback_);loop->RunOneFunc(std::bind(&TcpConnectionPtr::ConnectionEstablished, ptr));
}

3、acceptor.h


#ifndef TINY_MUDUO_ACCEPTOR_H_
#define TINY_MUDUO_ACCEPTOR_H_#include <functional>namespace tiny_muduo {class EventLoop;
class Address;
class Channel;class Acceptor {public:typedef std::function<void (int)> NewConnectionCallback;Acceptor(EventLoop* loop, const Address& address);void BindListenFd(const Address& address); void Listen();void NewConnection();void SetNewConnectionCallback(const NewConnectionCallback& callback) {new_connection_callback_ = callback;}private:EventLoop* loop_;int listenfd_;Channel* channel_;NewConnectionCallback new_connection_callback_;
};}
#endif

3、acceptor.cc


#include "acceptor.h"#include <assert.h>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <bits/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include <functional>#include "address.h"
#include "channel.h"using namespace tiny_muduo;namespace {const int kMaxListenNum = 5;
}Acceptor::Acceptor(EventLoop* loop, const Address& address): loop_(loop),listenfd_(socket(PF_INET, SOCK_STREAM, 0)),channel_(new Channel(loop, listenfd_)) {BindListenFd(address);channel_->SetReadCallback(std::bind(&Acceptor::NewConnection, this));
}void Acceptor::BindListenFd(const Address& addr) {struct sockaddr_in address;memset(&address, 0, sizeof(address));address.sin_family = AF_INET;address.sin_port = htons(addr.port());inet_pton(AF_INET, addr.ip(), &address.sin_addr); int ret = bind(listenfd_, (struct sockaddr*)(&address), sizeof(address));assert(ret != -1);
}void Acceptor::Listen() {int ret = listen(listenfd_, kMaxListenNum);assert(ret != -1);channel_->EnableReading();
}void Acceptor::NewConnection() {struct sockaddr_in client;socklen_t client_addrlength = sizeof( client );int connfd = accept(listenfd_, (struct sockaddr*)&client, &client_addrlength);new_connection_callback_(connfd);
}

4、channel.h


#ifndef TINY_MUDUO_CHANNEL_H_
#define TINY_MUDUO_CHANNEL_H_#include <sys/epoll.h>#include "eventloop.h"
#include "callback.h"namespace tiny_muduo {class Channel
{public:Channel(EventLoop* loop, const int& fd);~Channel();void HandleEvent();void SetReadCallback(const ReadCallback& callback) { read_callback_ = callback; }void SetWriteCallback(const WriteCallback& callback) {write_callback_ = callback;}void EnableReading() {events_ |= EPOLLIN; Update();  }void EnableWriting() {events_ |= EPOLLOUT;Update();}void Update() {loop_->Update(this);}void SetReceivedEvents(int events) {recv_events_ = events;}int fd()  { return fd_; } int events()  { return events_; }int recv_events() { return recv_events_; }private:EventLoop* loop_;int fd_;int events_;         // update eventsint recv_events_;    // epoll received eventsReadCallback read_callback_;WriteCallback write_callback_;
};}
#endif

4、channel.cc


#include "channel.h"#include <sys/epoll.h>using namespace tiny_muduo;Channel::Channel(EventLoop* loop,const int& fd): loop_(loop),fd_(fd),events_(0),recv_events_(0) {}void Channel::HandleEvent() {if (recv_events_ & EPOLLIN) {read_callback_();} else if (recv_events_ & EPOLLOUT) {write_callback_();} else {}
}

5、tcpconnectionptr.h


#ifndef TINY_MUDUO_TCPCONNECTIONPTR_H_
#define TINY_MUDUO_TCPCONNECTIONPTR_H_#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>#include <string> #include "callback.h"
#include "channel.h"using std::string;namespace tiny_muduo {class EventLoop;class TcpConnectionPtr {public:TcpConnectionPtr(EventLoop* loop,int connfd);~TcpConnectionPtr();void SetConnectionCallback(const ConnectionCallback& callback) { connection_callback_ = callback;}void SetMessageCallback(const MessageCallback& callback) {message_callback_ = callback;}void ConnectionEstablished() {channel_->EnableReading();connection_callback_(this);}void HandleMessage();void Send(const string& str);string Get();private:int Recv() {memset(buf_, '\0', sizeof(buf_));int ret = recv(connfd_, buf_, 100, 0);return ret;}EventLoop* loop_;int connfd_;Channel* channel_;char buf_[100] = {0};ConnectionCallback connection_callback_;MessageCallback message_callback_;
};}  // namespace tiny_muduo
#endif

5、tcpconnectionptr.cc


#include "tcpconnectionptr.h"#include <sys/types.h>
#include <sys/socket.h>#include "channel.h"using namespace tiny_muduo;TcpConnectionPtr::TcpConnectionPtr(EventLoop* loop, int connfd) : loop_(loop),connfd_(connfd),channel_(new Channel(loop_, connfd_)) {channel_->SetReadCallback(std::bind(&TcpConnectionPtr::HandleMessage, this));
}void TcpConnectionPtr::HandleMessage() {if (Recv() > 0) {message_callback_(this);}
}void TcpConnectionPtr::Send(const string& message) {strcpy(buf_,message.c_str());send(connfd_, (const void *)(buf_), sizeof(buf_), 0);
}std::string TcpConnectionPtr::Get() {string message(buf_);memset(buf_, '\0', sizeof(buf_));return message;
}

6、eventloop.h


#ifndef TINY_MUDUO_EVENTLOOP_H_
#define TINY_MUDUO_EVENTLOOP_H_#include <stdint.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>#include <vector>
#include <functional>#include "mutex.h"
#include "epoller.h"namespace tiny_muduo {class Epoller;
class Channel;class EventLoop {public:typedef std::vector<Channel*> Channels;typedef std::function<void()> BasicFunc; typedef std::vector<BasicFunc> ToDoList;  EventLoop();~EventLoop();bool IsInThreadLoop() { return ::pthread_self() == tid_; }void Update(Channel* channel) { epoller_->Update(channel); }void Loop();void HandleRead();void RunOneFunc(const BasicFunc& func);void DoToDoList();pthread_t DebugShowTid() { return tid_; }private:pthread_t tid_; Epoller* epoller_;int wakeup_fd_;Channel* wakeup_channel_;Channels active_channels_;ToDoList to_do_list_;MutexLock mutex_;
};}  // namespace tiny_muduo
#endif

6、eventloop.cc


#include "eventloop.h"#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>#include "mutex.h"
#include "channel.h"using namespace tiny_muduo;EventLoop::EventLoop(): tid_(::pthread_self()),epoller_(new Epoller()),wakeup_fd_(::eventfd(0, EFD_NONBLOCK)),wakeup_channel_(new Channel(this, wakeup_fd_)) {wakeup_channel_->SetReadCallback(std::bind(&EventLoop::HandleRead, this));wakeup_channel_->EnableReading();
}EventLoop::~EventLoop() {}void EventLoop::Loop() {while (1) {epoller_->Poll(active_channels_);for (const auto& channel : active_channels_) {channel->HandleEvent();}active_channels_.clear();DoToDoList();}
}void EventLoop::HandleRead() {uint64_t read_one_byte = 1;::read(wakeup_fd_, &read_one_byte, sizeof(read_one_byte));return;
}void EventLoop::RunOneFunc(const BasicFunc& func) { if (IsInThreadLoop()) {   func(); } else {{  MutexLockGuard lock(mutex_);to_do_list_.emplace_back(func);}   if (!IsInThreadLoop()) {uint64_t write_one_byte = 1;  ::write(wakeup_fd_, &write_one_byte, sizeof(write_one_byte));}   }
}void EventLoop::DoToDoList() {ToDoList functors;{MutexLockGuard lock(mutex_);functors.swap(to_do_list_);}for (const auto& func : functors) {func();}
}

7、epoller.h


#ifndef TINY_MUDUO_EPOLLER_H_
#define TINY_MUDUO_EPOLLER_H_#include <sys/epoll.h>
#include <vector>namespace {const int kMaxEvents = 8;
}namespace tiny_muduo {class Channel;class Epoller {public: typedef std::vector<epoll_event> Events;typedef std::vector<Channel*> Channels;Epoller();void Poll(Channels& channels);int EpollWait()  { return epoll_wait(epollfd_, &*events_.begin(), kMaxEvents, -1); }  int SetNonBlocking(int fd);void FillActiveChannels(int eventnums, Channels& channels); void Update(Channel* channel);void UpdateChannel(int operation, Channel* channel);private: int epollfd_;Events events_;
};}
#endif

7、epoller.cc


#include "epoller.h"#include <string.h>
#include <sys/epoll.h>
#include <fcntl.h>#include "channel.h"using namespace tiny_muduo;Epoller::Epoller(): epollfd_(epoll_create(kMaxEvents)),events_(kMaxEvents) {}void Epoller::Poll(Channels& channels) {int eventnums = EpollWait();FillActiveChannels(eventnums, channels);
}void Epoller::FillActiveChannels(int eventnums, Channels& channels) {for (int i = 0; i < eventnums; ++i) {Channel* ptr = static_cast<Channel*> (events_[i].data.ptr);ptr->SetReceivedEvents(events_[i].events);channels.emplace_back(ptr);}
}int Epoller::SetNonBlocking(int fd) {int old_state = fcntl(fd, F_GETFL);int new_state = old_state | O_NONBLOCK;fcntl(fd, F_SETFL, new_state);return new_state;
}void Epoller::Update(Channel* channel) {int op = 0, events = channel->events();if (events & EPOLLIN) {op = EPOLL_CTL_ADD;SetNonBlocking(channel->fd());} else if (events & EPOLLRDHUP) {op = EPOLL_CTL_DEL;} else {}UpdateChannel(op, channel);
}void Epoller::UpdateChannel(int operation, Channel* channel)
{struct epoll_event event;memset(&event, '\0', sizeof(struct epoll_event));event.events = channel->events() | EPOLLET;event.data.ptr = static_cast<void*>(channel);epoll_ctl(epollfd_, operation, channel->fd(), &event);return;
}

8、eventloopthreadpool.h(新增文件)


#ifndef TINY_MUDUO_EVENTLOOPTHREADPOOL_H_
#define TINY_MUDUO_EVENTLOOPTHREADPOOL_H_#include <vector>namespace tiny_muduo {class EventLoopThread;
class EventLoop;class EventLoopThreadPool {public:typedef std::vector<EventLoopThread*> Thread;typedef std::vector<EventLoop*> Loop;EventLoopThreadPool(EventLoop* loop);~EventLoopThreadPool();void SetThreadNums(int thread_nums) {thread_nums_ = thread_nums;}void StartLoop();EventLoop* NextLoop();private:EventLoop* base_loop_;   Thread threads_;Loop loops_;int thread_nums_;int next_;
};}
#endif

8、eventloopthreadpool.cc(新增文件)


#include "eventloopthreadpool.h"#include "eventloopthread.h"using namespace tiny_muduo;EventLoopThreadPool::EventLoopThreadPool(EventLoop* loop): base_loop_(loop),threads_(),loops_(),thread_nums_(0),next_(0) {}EventLoopThreadPool::~EventLoopThreadPool() {}void EventLoopThreadPool::StartLoop() {for (int i = 0; i < thread_nums_; ++i) {EventLoopThread* ptr = new EventLoopThread();threads_.emplace_back(ptr);loops_.emplace_back(ptr->StartLoop());}
}EventLoop* EventLoopThreadPool::NextLoop() {EventLoop* ret = base_loop_;if (!loops_.empty()) {ret = loops_[next_];next_ = (next_ + 1) % thread_nums_;}return ret;
}

9、eventloopthread.h(新增文件)


#ifndef TINY_MUDUO_EVENTLOOPTHREAD_H
#define TINY_MUDUO_EVENTLOOPTHREAD_H#include "thread.h"
#include "mutex.h"
#include "condition.h"namespace tiny_muduo {class EventLoop;class EventLoopThread {public:EventLoopThread();~EventLoopThread();void StartFunc();EventLoop* StartLoop();private:EventLoop* loop_;Thread thread_;MutexLock mutex_;Condition cond_;
};}
#endif

9、eventloopthread.cc(新增文件)


#include "eventloopthread.h"#include <pthread.h>
#include <functional>#include "mutex.h"
#include "condition.h"
#include "eventloop.h"using namespace tiny_muduo;EventLoopThread::EventLoopThread(): loop_(nullptr),thread_(std::bind(&EventLoopThread::StartFunc, this)),mutex_(),cond_(mutex_) {}EventLoopThread::~EventLoopThread() {}        EventLoop* EventLoopThread::StartLoop() {thread_.StartThread();EventLoop* loop = nullptr;{   MutexLockGuard lock(mutex_);while (loop_ == nullptr) {cond_.Wait();}loop = loop_;}return loop;
}void EventLoopThread::StartFunc() {EventLoop loop;{MutexLockGuard lock(mutex_);loop_ = &loop;cond_.Signal();}loop_->Loop();{MutexLockGuard lock(mutex_);loop_ = nullptr;}
}

10、thread.h(新增文件)


#ifndef TINY_MUDUO_THREAD_H_
#define TINY_MUDUO_THREAD_H_#include <pthread.h>#include <functional>#include "latch.h"namespace tiny_muduo {class Thread {public:typedef std::function<void ()> ThreadFunc;Thread(const ThreadFunc& func);~Thread(); void StartThread();private:pthread_t pthread_id_;ThreadFunc func_;Latch latch_;
};       struct ThreadData {typedef tiny_muduo::Thread::ThreadFunc ThreadFunc;ThreadFunc func_;
Latch* latch_;ThreadData(ThreadFunc& func, Latch* latch): func_(func),latch_(latch) {}void RunOneFunc() {latch_->CountDown();latch_ = nullptr;  func_();
}
};}
#endif

10、thread.cc(新增文件)


#include "thread.h"#include <pthread.h>#include "latch.h"using namespace tiny_muduo;static void* ThreadRun(void* arg) {ThreadData* ptr = static_cast<ThreadData*>(arg);ptr->RunOneFunc();delete ptr;return nullptr;
}Thread::Thread(const ThreadFunc& func): pthread_id_(-1),func_(func),latch_(1) {}Thread::~Thread() {::pthread_detach(pthread_id_);
}void Thread::StartThread() {ThreadData* ptr = new ThreadData(func_, &latch_);::pthread_create(&pthread_id_, nullptr, ThreadRun, ptr);latch_.Wait();
}

3、其他组件(Address、Callback、Mutex、Condition、makefile等等)


1、address.h


#ifndef TINY_MUDUO_ADDRESS_H_
#define TINY_MUDUO_ADDRESS_H_#include <string>
#include <cstring>namespace tiny_muduo {class Address {private:const char* ip_;const int port_;public:Address(const char* port = "2022") : ip_("127.0.0.1"), port_(atoi(port)) {}const char* ip() const { return ip_; }const int port() const { return port_; }
};}
#endif

2、callback.h


#ifndef TINY_MUDUO_CALLBACK_H_
#define TINY_MUDUO_CALLBACK_H_#include <functional>using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;namespace tiny_muduo {class TcpConnectionPtr;typedef std::function<void (TcpConnectionPtr*)> ConnectionCallback;typedef std::function<void (TcpConnectionPtr*)> MessageCallback;typedef std::function<void ()> ReadCallback;typedef std::function<void ()> WriteCallback;
}
#endif

3、mutex.h(新增文件)


#ifndef TINY_MUDUO_MUTEX_H_
#define TINY_MUDUO_MUTEX_H_#include "pthread.h"namespace tiny_muduo {class MutexLock {public:MutexLock() {pthread_mutex_init(&mutex_, nullptr);}~MutexLock() {pthread_mutex_destroy(&mutex_);}bool Lock() {return pthread_mutex_lock(&mutex_) == 0;}bool Unlock() {return pthread_mutex_unlock(&mutex_) == 0; }pthread_mutex_t* mutex() { return &mutex_; } private:pthread_mutex_t mutex_;
};class MutexLockGuard {public:MutexLockGuard(MutexLock& mutex) : mutex_(mutex) {mutex_.Lock();}~MutexLockGuard() {mutex_.Unlock();}private:MutexLock& mutex_;
};}
#endif

4、condition.h(新增文件)


#ifndef TINY_MUDUO_CONDITION_H_
#define TINY_MUDUO_CONDITION_H_#include "pthread.h"#include "mutex.h"namespace tiny_muduo {class Condition {public:Condition(MutexLock& mutex) : mutex_(mutex) {pthread_cond_init(&cond_, nullptr);}~Condition() {pthread_cond_destroy(&cond_);}bool Wait() {int ret = 0;ret = pthread_cond_wait(&cond_, mutex_.mutex());return ret == 0;}bool Signal() {return pthread_cond_signal(&cond_);}bool BroadCast() {return pthread_cond_broadcast(&cond_);}private:MutexLock& mutex_;pthread_cond_t cond_;
}; }
#endif

5、latch.h(新增文件)


#ifndef TINY_MUDUO_LATCH_H_
#define TINY_MUDUO_LATCH_H_#include "mutex.h"
#include "condition.h"namespace tiny_muduo {class Latch {public:Latch(int count) : count_(count), mutex_(), cond_(mutex_) {}void CountDown() {MutexLockGuard lock(mutex_);--count_;if (count_ == 0) {cond_.BroadCast();}  }void Wait() {MutexLockGuard lock(mutex_);while (count_ > 0) {cond_.Wait();}}private:int count_;MutexLock mutex_;Condition cond_;
};}
#endif

6、makefile(注意链接 -lpthread)


CC = g++
CFLAG = -Wall -c
OBJS = main.o echo.o tcpserver.o acceptor.o\channel.o eventloop.o epoller.o tcpconnectionptr.o\eventloopthreadpool.o eventloopthread.o thread.o $(TFLAG)
TFLAG = -lpthreadweb_server : $(OBJS) $(CC) $^ -o $@main.o : main.cc eventloop.h address.h echo.h$(CC) $(CFLAG) $< -o $@echo.o : echo.cc echo.h tcpserver.h$(CC) $(CFLAG) $< -o $@tcpserver.o : tcpserver.cc tcpserver.h acceptor.h tcpconnectionptr.h\eventloopthreadpool.h$(CC) $(CFLAG) $< -o $@acceptor.o : acceptor.cc acceptor.h address.h channel.h$(CC) $(CFLAG) $< -o $@channel.o : channel.cc channel.h$(CC) $(CFLAG) $< -o $@eventloop.o : eventloop.cc eventloop.h channel.h mutex.h$(CC) $(CFLAG) $< -o $@eventloopthreadpool.o : eventloopthreadpool.cc eventloopthreadpool.h eventloopthread.h$(CC) $(CFLAG) $< -o $@eventloopthread.o : eventloopthread.cc eventloopthreadpool.h mutex.h\condition.h eventloop.h$(CC) $(CFLAG) $< -o $@thread.o : thread.cc thread.h latch.h$(CC) $(CFLAG) $< -o $@epoller.o : epoller.cc epoller.h channel.h$(CC) $(CFLAG) $< -o $@tcpconnectionptr.o : tcpconnectionptr.cc tcpconnectionptr.h \channel.h$(CC) $(CFLAG) $< -o $@.PHONY : clean
clean:rm *.o

4、tiny_muduo echo(One Loop Per Thread + Thread Pool 默认8线程) test


下面大致放一张图吧 我自己大致测试了一下 确实是8个线程轮流接受任务 回调那些也是基本上正常的 那么简单的测试就到这里了


结束语


老规矩 放一张自己平时的工作界面 就是轮流看着这些个小窗口 然后点来点去的 没其他啥了

感冒了 估计有点点严重 但还好 各位还是多注意一下身体吧 身体是最重要的 这段时间早晚温差大 注意保暖

这篇就先写到这里吧 写完回去点个外卖 吃点药就在床上躺着了 估计之后还会写个好几篇吧 毕竟说实话 还有太多太多地方需要改了 还有一些小组件 涉及效率的 也要改 我看着我的tcpconnection读写 我都看不下去 还有后面还要认真看一下 内存泄漏 如何用shared_ptr unique_ptr weak_ptr来管理内存 和 完成线程安全的工作呢 这里还是相当重要的

总之还有很长的路要走 当然 走到现在回想起前段时间 连入手都不知道怎么入 到现在基本框架都被我嗯整整出来了 哈哈 想着还是开心的
可能是功夫不负有心人吧 或者是上天还是一直非常眷顾我的 毕竟平时也是善人一个 尽管很喜欢口嗨 有的时候还会骂人 哈哈
但是从结果上来看 到现在是好的 那就够了

好了 那这篇博客就先写到这里吧 我也收拾收拾电脑 收拾收拾书 把药拿着 回寝室休息了 回去好好休息休息 各位下篇再见了~

从零开始自制实现WebServer(五)---- 浅沿芳草鲜花小路静心踱步 拨云见雾终见多线程ThreadPool相关推荐

  1. 从零开始自制实现WebServer(六)---- 跌跌撞撞奔向HTTP状态机 学习途中拾慧纠正过往细节偏差

    文章目录 全流程实现博客链接 前引 (六)跌跌撞撞奔向HTTP状态机 学习途中拾慧纠正过往细节偏差 1.工欲行其事 必先利其器 buffer横空出世 1.buffer.h 2.buffer.cc 2. ...

  2. 从零开始自制实现WebServer(十八)---- 对服务器做最后的压力测试 WebBench压测小工具 项目迎来终章

    文章目录 全流程实现博客链接 前引 (十八)---- 对服务器做最后的压力测试 WebBench压测小工具 项目迎来终章 1.正确处理Vmware-Station 处理器设置(初步调试过程) 2.正确 ...

  3. 从零开始自制实现WebServer(十九)---- 正式系统的学习一下Git 捣鼓捣鼓github以及一些其他的小组件

    文章目录 全流程实现博客链接 前引 (十九)---- 正式系统的学习一下Git 捣鼓捣鼓github以及一些其他的小组件 1.悔!为什么不在一开始做项目的时候就用Git 错过学习实践Git的最好机会 ...

  4. 从零开始自制实现WebServer(十六)---- 学习新工具CMake自动编写MakeFile 分门别类整理源文件心情愉悦

    文章目录 全流程实现博客链接 前引 (十六)---- 学习新工具CMake自动编写MakeFile 小改小动项目接近尾声 1.学习新工具 cmake / shell脚本 需要耐心与时间 2.分门别类整 ...

  5. 《操作系统真象还原》从零开始自制操作系统 全流程记录

    文章目录 前引 章节博客链接 实现源码链接 前引 这本<操作系统真象还原>里面一共有十五个章节 大约760页 这些系列博客也是我在做完哈工大操作系统Lab之后 觉得还是有些朦朦胧胧 毅然决 ...

  6. 从零开始自制实现正则引擎 全流程记录

    文章目录 前引 Regex_Engine 1.0 1.全流程实现博客链接 2.源码仓库链接 前引 笔者在完成 正则引擎初版 如果算上有效时间的话 大概是花了一周的时间就完成 只包括了 最基础的正则引擎 ...

  7. 【Visual C++】游戏开发五十五 浅墨DirectX教程二十二 水乳交融的美学:alpha混合技术

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/15026917 作者:毛星 ...

  8. 【Visual C++】游戏开发笔记四十五 浅墨DirectX教程十三 深度测试和Z缓存专场

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8607864 作者:毛星云(浅墨 ...

  9. 从零开始的linux 第五章

    从零开始的linux 第五章 (咚咚咚...)路人甲:"小编!!快起床!!今天该讲课啦!" (迷迷糊糊且衣冠不整的小编去开门) 路人甲:"小...小编大人...你都让我这 ...

最新文章

  1. 几个流行移动前端框架的比较评分
  2. wxml 点击图片下载_云存储之上传图片和展示图片(小程序云开发)
  3. Jenkins定时构建任务
  4. debian下为python2.7 安装MySQLdb扩展(mariadb)
  5. 【Uva 1625】Color Length
  6. create maven android project
  7. 使用VS2008怎么连接自带的SQL Server2005的Express版本数据库
  8. DS之信息挖掘:利用pandas库统计某一列col中各个值出现的次数(降序输出)
  9. kmeans改进 matlab,基于距离函数的改进k―means 算法
  10. benchmark如何测试mysql数据库_MySQL的benchmark函数
  11. SpringMVC源码阅读(三)
  12. 液晶手写板原理拆解_汽车抬头显示HUD的拆解
  13. python 图像识别_AI场景,3步懂图像识别产品
  14. C语言scanf输入a3,【C语言】04 printf和scanf函数
  15. 如何区分oracle服务器、oracle客户端、plsql?
  16. 专题四——线段树、树状数组
  17. 小程序wxParse
  18. python 结巴分词学习
  19. Windows 上安装vmware到Ubuntu到python到umake到Pip 到pycharm
  20. IPtables中SNAT、DNAT和MASQUERADE的含义

热门文章

  1. UVa 10306 - e-Coins
  2. uva10306 - e-Coins(完全背包)
  3. R 填充数据集中的缺失值
  4. 在hbuilder制作APP时使用echarts:堆叠柱状图
  5. Android Studio中如何将ijkplayer 0.6.3导入自己的项目中并使用
  6. caffe 损失函数
  7. 我厌倦玩计算机游戏了英语翻译,我喜欢玩电子游戏英文翻译,我喜欢电脑游戏怎么说...
  8. c语言 simon 游戏,终于发现少儿英语游戏SimonSays(西蒙说)
  9. AD转换中【参考电压】的作用
  10. android studio模拟器出错,A resource failed to call close