libevent 多线程

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

仅支持vs2012及以上。

#pragma once
#include <functional>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>

#include "event2/event_struct.h" // for: struct event

struct 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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值