libevent 多线程

来源:互联网 发布:域名收费标准 编辑:程序博客网 时间:2024/05/22 04:55

一个线程一个event_base,代码仅做练习使用,没有考虑销毁。

仅支持vs2012及以上。

#pragma once#include <functional>#include <condition_variable>#include <mutex>#include <thread>#include <vector>#include "event2/event_struct.h" // for: struct eventstruct event_base;struct bufferevent;class EventLoopThread{public:typedef std::function<void()> Functor;EventLoopThread();~EventLoopThread();struct event_base *startLoop();void runInLoop(const Functor &cb);std::thread::id getThreadID() const { return threadID_; }private:void wakeup();static void WakeupCallback(evutil_socket_t, short, void *arg);void threadFunc();struct event_base *base_;bool exiting_;std::thread thread_;std::mutex mutex_;std::condition_variable cond_;std::vector<Functor> functors_;evutil_socket_t wakeFd_[2];evutil_socket_t connFd_;struct event ev_;std::thread::id threadID_;};class EventLoopThreadPool{public:EventLoopThreadPool();~EventLoopThreadPool();void setThreadNum(int num);void start();EventLoopThread *getNextLoop();std::thread::id currentThreadID() const;private:std::vector<EventLoopThread*> loops_;int num_;int next_;};class Channel{public:typedef std::function<void(struct bufferevent *bev)> ReadCallback;typedef ReadCallback WriteCallback;typedef std::function<void(struct bufferevent *bev, short what)> EventCallback;Channel(struct event_base *base, evutil_socket_t fd);~Channel();void start();private:Channel(const Channel&);Channel& operator=(const Channel&);static void readCallback(struct bufferevent *bev, void *data);static void writeCallback(struct bufferevent *bev, void *data);static void eventCallback(struct bufferevent *bev, short what, void *data);private:ReadCallback readCallback_;WriteCallback writeCallback_;EventCallback eventCallback_;struct bufferevent *bufferEvent_;};class TcpServer{public:TcpServer(unsigned short port);~TcpServer();void start();private:TcpServer(const TcpServer&);TcpServer& operator=(const TcpServer&);static void listenCallback(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg);private:unsigned short port_;struct evconnlistener *listener_;EventLoopThreadPool eventPool_;};


 

#include "stdafx.h"#include <iostream>#include "EventLoopThread.h"#include "event2/event.h"#include "event2/event_struct.h"#include "event2/util.h"#include "event2/buffer.h"#include "event2/listener.h"#include "event2/bufferevent.h"EventLoopThread::EventLoopThread(): base_(NULL), exiting_(false), thread_(std::bind(&EventLoopThread::threadFunc, this)), threadID_(thread_.get_id()){}EventLoopThread::~EventLoopThread(){exiting_ = true;event_base_loopexit(base_, NULL);thread_.join();}struct event_base *EventLoopThread::startLoop(){{std::unique_lock<std::mutex> ul(mutex_);while (NULL == base_) {cond_.wait(ul);}}return base_;}void EventLoopThread::runInLoop(const Functor &cb){{std::lock_guard<std::mutex> lock(mutex_);functors_.push_back(cb);}wakeup();}void EventLoopThread::wakeup(){char c = 'w';::send(wakeFd_[0], &c, 1, 0);}void EventLoopThread::WakeupCallback(evutil_socket_t fd, short, void *arg){EventLoopThread *p = (EventLoopThread*)arg;if (p) {char buf[16] = {0};::recv(p->wakeFd_[1], buf, sizeof(buf), 0);std::vector<Functor> functors;{std::lock_guard<std::mutex> lock(p->mutex_);functors.swap(p->functors_);}for (auto& f : functors) {f();}}}void EventLoopThread::threadFunc(){struct event_base *base = event_base_new();int iret = evutil_socketpair(AF_INET, SOCK_STREAM, 0, wakeFd_);std::cout << "socket pair ret:" << iret << std::endl;iret = event_assign(&ev_, base, wakeFd_[1], EV_READ | EV_PERSIST, WakeupCallback, this);if (0 != iret) {std::cout << "event assign error" << iret << std::endl;}iret = event_add(&ev_, NULL);if (0 != iret) {std::cout << "event add error" << iret << std::endl;}{std::unique_lock<std::mutex> ul(mutex_);base_ = base;cond_.notify_one();}event_base_dispatch(base);printf("event loop exiting ...\n");}///////////////////////////////////////////////////////////////////////////////////////////EventLoopThreadPool::EventLoopThreadPool(): num_(1) , next_(0){}EventLoopThreadPool::~EventLoopThreadPool(){for (auto loop : loops_) {delete loop;}}void EventLoopThreadPool::setThreadNum(int num){num_ = num;}void EventLoopThreadPool::start(){for (int i=0; i<num_; i++) {EventLoopThread *loop = new EventLoopThread();loops_.push_back(loop);}}EventLoopThread* EventLoopThreadPool::getNextLoop(){EventLoopThread *pCurrent = loops_[next_++];next_ %= num_;return pCurrent;}std::thread::id EventLoopThreadPool::currentThreadID() const{if (next_ - 1 >= 0) {return loops_[next_ - 1]->getThreadID();} else {return std::thread::id();}}////////////////////////////////////////////////////////////////////////////////////////////Channel::Channel(struct event_base *base, evutil_socket_t fd): bufferEvent_(bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE)){}Channel::~Channel(){// FIXME}void Channel::start(){bufferevent_setcb(bufferEvent_, readCallback, writeCallback, eventCallback, this);int iret = bufferevent_enable(bufferEvent_, EV_READ | EV_WRITE);if (0 != iret) {std::cout << "bufferevent enable error" << std::endl;}}void Channel::readCallback(struct bufferevent *bev, void *data){fprintf(stdout, "ReadCallback..., threadID:%d\n", ::GetCurrentThreadId());struct evbuffer *input = bufferevent_get_input(bev);size_t len = evbuffer_get_length(input);evbuffer_drain(input, len);fprintf(stdout, "drain, len:%d\n", len);//struct evbuffer *output = bufferevent_get_output(bev);//size_t len = evbuffer_get_length(input);//evbuffer_remove_buffer(input, output, len);}void Channel::writeCallback(struct bufferevent *bev, void *data){fprintf(stdout, "WriteCallback..., threadID:%d\n", ::GetCurrentThreadId());struct evbuffer *output = bufferevent_get_output(bev);}void Channel::eventCallback(struct bufferevent *bev, short what, void *data){if (!data) {return;}Channel *p = (Channel*)data;fprintf(stdout, "EventCallback...\n");if (what & BEV_EVENT_READING) {fprintf(stdout, "BEV_EVENT_READING...\n");}if (what & BEV_EVENT_WRITING) {fprintf(stdout, "BEV_EVENT_WRITING...\n");}if (what & BEV_EVENT_EOF) {fprintf(stdout, "BEV_EVENT_EOF...\n");}if (what & BEV_EVENT_ERROR) {fprintf(stdout, "BEV_EVENT_ERROR...\n");bufferevent_free(bev);}if (what & BEV_EVENT_TIMEOUT) {fprintf(stdout, "BEV_EVENT_TIMEOUT...\n");}if (what & BEV_EVENT_CONNECTED) {fprintf(stdout, "BEV_EVENT_CONNECTED...\n");}}TcpServer::TcpServer(unsigned short port): port_(port){}TcpServer::~TcpServer(){}void TcpServer::start(){eventPool_.setThreadNum(3);eventPool_.start();struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.s_addr = htonl(0);sin.sin_port = htons(port_);struct event_base *base = event_base_new();evconnlistener_new_bind(base, listenCallback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,-1, (sockaddr*)&sin, sizeof(sin));event_base_dispatch(base);}void TcpServer::listenCallback(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg){if (!arg)  {return; }fprintf(stdout, "new connection is comming...\n");TcpServer *p = (TcpServer*)arg;EventLoopThread *loop = p->eventPool_.getNextLoop();Channel *channel = new Channel(loop->startLoop(), fd);loop->runInLoop(std::bind(&Channel::start, channel));fprintf(stdout, "currentThreadID:%d\n", loop->getThreadID());}


 

#include "stdafx.h"#include <iostream>#include "EventLoopThread.h"int _tmain(int argc, _TCHAR* argv[]){WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);{TcpServer tcpServer(5100);tcpServer.start();}system("pause");WSACleanup();return 0;}


 

0 0