使用libevent编写多线程服务端
一、设计框架:
1)主线程监听连接各种事件,创建多个工作线程处理具体业务
2)收到连接时创建对象管理,并绑定到一个线程
3)主线程监听到一个读事件,将该连接添加到所绑定的线程的处理队列
4)工作线程一次取出队列元素,从bufferevent读取数据,并处理
二、、设置bufferevent为多线程安全(也就是每次读写bufferevent都是上锁的)
1)设置多线程支持
#ifdef WIN32
evthread_use_windows_threads();
#else
evthread_use_pthreads();
#endif
2)创建bufferevent时加上BEV_OPT_THREADSAFE标志
struct bufferevent *bev = NULL;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
3)此后使用bufferevent缓存就是线程安全的
当然在自己的代码中也可以使用bufferevent的锁
bufferevent_lock(bev);
/*............中间这部分已经加锁...........*/
bufferevent_unlock(bev);
三、使用智能指针(std::shared_ptr<type> nodeptr(new type))管理连接对象
1)原因:
创建了一个对象来管理一个连接(bufferevent),在多线程中,可能主线程监听到断开连接,这时就会删除该对象,但是,此时可能工作线程中正通过对象对连接的数据进行处理,如果删除了该对象,造成的后果很可能时段错误-程序崩溃。
2)因此:
收到连接时创建一个智能指针指向连接对象,并用容器保存。
收到连接读事件时,将该连接对象的智能指针传到工作线程的处理队列。
线程取出智能指针后,通过该智能指针调用对象接口。
此时,及时主线程从容器中删除了该智能指针,但是线程中正通过同一对象的智能指针调用对象,对象实际上就不会删除,只有等待工作线程处理结束并跳出智能指针的栈范围,连接对象才会实际删除。
如果工作线程处理完对象后,需要向连接写数据,那么一定要注意加锁、加判断条件,因为此时可能连接已经断开了。