今天进一步封装了线程类,并对服务器类进行了简单的封装测试,具体过程如下:
- 利用event_base_dispatch实现线程池中子线程的功能,即客户端的功能,代码如下:
printf ("线程:%d 开始运行\n", (int) m_threadId);
//监听事件集合
//event_base_dispatch死循环,用来处理事件集合
//当事件集合m_base为空的时候,event_base_dispatch会立马返回
//在初始化的时候就令m_base这个事件集合不为空
event_base_dispatch(m_base);
event_base_free(m_base);
printf ("线程:%d 结束运行\n", (int) m_threadId);
- 为了使m_base初始化的时候不为空,添加初始事件,建立主线程和子线程之间的管道,设定主线程为管道的写端,子线程为管道的读端,代码如下:
//创建管道
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
m_pieReadFd = pipefd [0];
m_pieWriteFd = pipefd [1];
//添加管道事件添加到m_base的事件集合
event_set (&m_pipeEvent, m_pieReadFd, EV_READ | EV_PERSIST, pipeCb, this);
event_base_set (m_base, &m_pipeEvent);
event_add (&m_pipeEvent, 0);
pipe的用法可以用man指令查询,在此过程中,需要用两个变量来存储pipefd即pipe的文件描述符,fd的含义可参考以下文章:fd
在该过程中还用到了回调函数pipeCb,在这里只是为了测试线程类封装的完整性,先置该函数为空。
进一步的,event_set需要一个struct event类型的变量,因此需要在头文件中创建一个变量来存储事件,struct event在头文件中已经定义好 ,我们只需要在类中声明即可,修改后的头文件如下:
#ifndef THREAD_H
#define THREAD_H
#include <event2/event.h>
#include <event.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
class Thread
{
private:
struct event_base *m_base;
pthread_t m_threadId;
int m_pieReadFd; //管道的写端
int m_pieWriteFd; //管道的读端
struct event m_pipeEvent;
public:
Thread ();
~Thread ();
void run (); //线程的逻辑函数
void start (); //线程的运行函数
protected:
static void *worker (void *); //线程的工作函数
static void pipeCb(int, short, void *); //线程的回调函数
};
#endif
- 执行指令编译源码并运行,结果如下
运行结果正常,顺利完成线程类的封装。