------------------------------------ Linux线程池加上epoll -------------------------------


Lock.cpp : 锁的操作 , 读锁可以并发 , 写锁独占.

Queue.h : 队列的封装 , 队列的读和写都加了锁的保护.

Socket.cpp : 套接口的简单封装.

Thread.cpp : 线程的封装实现了些简单的线程停止,运行等功能 , 启动别的线程的时候需要继承次类.

Worker.cpp : 用户接口类 , 用户需继承此类。

ListenThread.cpp(继承Thread.cpp) : 服务器监听线程.如果有客户端连接通知ThreadPool类,由ThreadPool类进行任务分派.

TaskThread.cpp(继承Thread.cpp) : 具体任务类,负责接受客户端发送数据.

ThreadPool.cpp (继承Thread.cpp) : 线程池类负责启动别的线程 , 并且进行线程调度。首先启动ListenThread.cpp类,如果有客户端

连接ListenThread.cpp类发送信号通知ThreadPool.cpp类,收到信号再分配给TaskThread.cpp类,进行处理。如果没有空闲任务类,动态再

创建一定数目的任务类。


这只是一个线程池的框架还有许多不足 : 没有实现server->client数据发送 , 还有许多细节没有完善。


(TaskThread没有实现,需要自己实现。具体的数据的交互,没看到。接受线程开了好几个。难道主要的屏障在这里?任务线程类,耗费资源不多,处理很快?一个线程就ok?)

///
/// @file def.h
/// @brief
/// @author guozhiming
/// @date 2007-04-11
///
#ifndef __DEF__
#define __DEF__
#include <iostream>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <deque>
#include <signal.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <map>
using namespace std;
typedef unsigned long ULONG;
/// @brief 为了服务器接收到client的信息把数据和client的套接字连接到一起
struct G_DataSocket
{
    int nSocket;
    void *pStr;
};
//sock加str?str只是string?一个sock对应一个buf,ip,port等数据也没记录,要是udp呢?struct addr_in
#endif
///
/// @file Thread.h
/// @brief 线程的封装 , 子类继承并实现自己的功能
/// @author guozhiming
/// @date 2007-05-16
///
#ifndef __G_THREAD__
#define __G_THREAD__
#include "def.h"
class G_Thread
{
    public:
        /// @brief 构造函数
        G_Thread();
        /// @brief 析构函数
        ~G_Thread();
        /// @brief 获得线程id
        ///
        /// @return 线程id
        pthread_t getThreadId();
        /// @brief 启动线程
        bool Start();
        /// @brief 线程停止
        void pause();
        /// @brief 线程继续运行
        void continues();
    private:
        /// @brief  屏蔽SIGUSR1信号 , POSIX标准建议在调用sigwait()等待信号以前,进程中所有线程都应屏蔽该信号,以保证仅有sigwait()的调用者获得该信号 , 如果不屏蔽该信号,在sigwait()之前调用pthread_kill()就会出现User defined signal 1.这么复杂的东西,以前没用过这个信号。。
        void maskSIGUSR1();
        /// @brief 线程pid
        pthread_t g_pid;
        /// @brief 信号
        sigset_t g_waitSig;
        /// @brief 线程运行主函数
        ///
        /// @param arg
        ///
        /// @return 这里又来一个,和run函数争抢
        static void *threadFun(void *arg);
    protected:
        virtual void Run() = 0;//主要的应该在run里运行。
};
#endif


#include "Thread.h"
#include "Log.h"
G_Thread::G_Thread()
{
    maskSIGUSR1();
    // 定义SIGUSR1信号阻塞
    sigemptyset(&g_waitSig);
    sigaddset(&g_waitSig, SIGUSR1);//sigusr1是用户自定义的信号,这里把他定义为阻塞信号。。。
}
G_Thread::~G_Thread()
{
}
void G_Thread::maskSIGUSR1()
{
    sigset_t sig;
    sigemptyset(&sig);
    sigaddset(&sig , SIGUSR1);
    pthread_sigmask(SIG_BLOCK , &sig , NULL);//mask掉。。
}
pthread_t G_Thread::getThreadId()
{
    return g_pid;
}
void *G_Thread::threadFun(void *arg)
{
    G_Thread *pThread = (G_Thread*)arg;
    pThread->Run();//还是靠run函数
}
bool G_Thread::Start()
{
//不是线程池创建吗?这里create干嘛
    int nRet = pthread_create(&g_pid , NULL , threadFun , this);
    if(0 == nRet)
    {
        nRet = pthread_detach(g_pid);
        if(nRet == 0)
        {
            return true;
        }
    }
    else
    {
        return false;
    }
    return true;
}
void G_Thread::pause()
{
    int sig;
    sigwait(&g_waitSig , &sig);//等什么信号?会来什么信号?
}
void G_Thread::continues()
{
    pthread_kill(g_pid , SIGUSR1);//关系吖。什么关系。。杀了这个信号,就行继续运行。是这个信号,造成的堵塞?那么谁来发这个kill呢?
}
///
/// @file Socket.h
/// @brief 套接口的简单封装
/// @author guozhiming
/// @date 2007-05-16
///
#ifndef __G_SOCKET__
#define __G_SOCKET__
#include "def.h"
class G_Socket
{
    public:
        /// @brief 构造函数
        G_Socket();
        /// @brief 析构函数
        ~G_Socket();
//这个socket只是服务端tcp,不能用来client。。
        /// @brief 服务器帮定端口
        ///
        /// @param nPort 帮定端口
        ///
        /// @return true表示成功 , false表示失败
        bool Bind(unsigned int nPort);
        /// @brief 如果有client连接得到套接字
        ///
        /// @param nSocket 返回套接字
        ///
        /// @return true 表示获得套接字成功 , false 表示获得套接字失败
        bool Listen(int &nSocket);
    private:
        /// @brief 套接字
        int g_sockfd;
        /// @brief epoll_create 返回文件描述符
        int epfd;
//只定义100个,这怎么算高并发?搞这么复杂的结构,才100events
        struct epoll_event events[100];
        /// @brief 设置套接口非阻塞模式
        ///
        /// @param sockfd 套接口
        ///
        /// @return true 成功 , false 失败
        bool setNonBlock(int sockfd);
};
#endif
#include "Socket.h"
#include "Log.h"
                                                            
G_Socket::G_Socket()
{
    epfd = epoll_create(256);
}
G_Socket::~G_Socket()
{
    close(g_sockfd);
    close(epfd);
}
bool G_Socket::setNonBlock(int sockfd)
{
    int opts = fcntl(sockfd , F_GETFL);
    if(-1 == opts)
    {
        debug_output("%s\n" , "fcntl F_GETFL is faild");
        return false;
    }
    opts = opts | O_NONBLOCK;
    if(fcntl(sockfd , F_SETFL , opts) < 0)
    {
        debug_output("%s\n" , "fcntl F_SETFL is faild");
        return false;
    }
    return true;
}
bool G_Socket::Bind(unsigned int nPort)
{
    g_sockfd = socket(PF_INET , SOCK_STREAM , 0);
    if(-1 == g_sockfd)
    {
        debug_output("%s\n" , "Create Socket is faild");
        return false;
    }
    /// 允许地址重用
    int reuse = 1;
    setsockopt(g_sockfd , SOL_SOCKET , SO_REUSEADDR , &reuse , sizeof(reuse));
    bool bRet = setNonBlock(g_sockfd);
    if(bRet == false)
    {
        return false;
    }
    struct sockaddr_in servaddr;
    bzero(&servaddr , sizeof(servaddr));
    servaddr.sin_family = PF_INET;
    servaddr.sin_port = htons(9999);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    int nRet = bind(g_sockfd , (struct sockaddr*)&servaddr , sizeof(servaddr));
    if(-1 == nRet)
    {
        debug_output("%s\n" , "bind is faild");
        return false;
    }
    nRet = listen(g_sockfd , 128);
    if(-1 == nRet)
    {
        debug_output("%s\n" , "listen is faild");
        return false;
    }
    struct epoll_event ev;
    bzero(&ev , sizeof(ev));
    ev.data.fd = g_sockfd;
    ev.events = EPOLLIN | EPOLLET;
    nRet = epoll_ctl(epfd , EPOLL_CTL_ADD , g_sockfd , &ev);
    if(-1 == nRet)
    {
        debug_output("%s\n" , "epoll_ctl is faild");
        return false;
    }
    return true;
}
bool G_Socket::Listen(int &nSocket)
{
    static int counter = 0;
    int nfds , i;
    while(1)
    {
        nfds = epoll_wait(epfd , events , 100 , 500);//最多100个?so less!!!
        for(i=0; i<nfds; i++)
        {
            if(events[i].data.fd == g_sockfd)
            {
                nSocket = accept(g_sockfd , NULL , NULL);
                debug_output("nSocket = %d\n" , nSocket);
                if(nSocket == -1)
                {
                    if(errno == EINTR)
                    {
                        continue;
                    }
                    debug_output("%s\n" , "accept is faild");
                    return false;
                }
                debug_output("counter = %d\n" , ++counter);
                return true;
            }
        }
    }
}
///
/// @file ListenThread.h
/// @brief 服务器监听线程
/// @author guozhiming
/// @date 2007-05-16
///
#ifndef __G_LISTENTHREAD__
#define __G_LISTENTHREAD__
#include "Thread.h"
#include "Socket.h"
#include "ThreadPool.h"
class G_ThreadPool;
class G_ListenThread : public G_Thread
{
    public:
        /// @brief 构造函数,这个G_ThreadPool ,是定义一个实例?还是定义好几个pool?
        G_ListenThread(G_ThreadPool *pool);
        /// @brief 析构函数
        virtual ~G_ListenThread();
        /// @brief
        void Run();
        /// @brief 服务器帮定端口
        ///
        /// @param nPort 帮定端口
        ///
        /// @return true表示成功 , false表示失败
        bool Bind(unsigned int nPort);
    private:
                                                  
        ///套接口操作的对象
        G_Socket *g_socket;
        G_ThreadPool *g_threadPool;//这里就包含池子。
};
#endif
#include "ListenThread.h"
#include "Log.h"
//这样,就是线程池的一员了。不过线程池,好像没调度你
G_ListenThread::G_ListenThread(G_ThreadPool *pool) : g_threadPool(pool)
{
    g_socket = new G_Socket();
}
G_ListenThread::~G_ListenThread()
{
    if(g_socket)
    {
        delete g_socket;
        g_socket = NULL;
    }
}
void G_ListenThread::Run()
{
    pause();//看不懂,暂停,,什么时候开始。?有信号时,会中断此函数。什么信号,什么时候来?要有kill才能对应到这里,结束暂停状态
    debug_output("Listen thread is starting ....\n");
                
    int nSocket;
    while(1)
    {
        if(g_socket->Listen(nSocket))
        {
            debug_output("new client is connecting ....\n");//新的连接?那socket是客户端的socket??
            g_threadPool->pushSocket(nSocket);   ///填加到套接口队列//这里放的是server的socket啊??
            //监听到了,就放到池子里
            g_threadPool->continues();   ///通知线程池,运行起来,到套接口队列中取套接口
        }
    }
}
bool G_ListenThread::Bind(unsigned int nPort)
{
    if(!g_socket->Bind(nPort))
    {
        debug_output("Bind port %d is faild\n" , nPort);
        return false;
    }
    debug_output("Bind port %d is Successful\n" , nPort);
    continues();
    return true;
}
///
/// @file TaskThread.h
/// @brief 任务类 , 接受client发的消息进行处理
/// @author guozhiming
/// @date 2007-05-17
///
#ifndef __TASKTHREAD__
#define __TASKTHREAD__
#include "def.h"
#include "Thread.h"
#include "ThreadPool.h"
#include "Queue.h"
#include "Data.h"
class G_ThreadPool;
class G_Data;
class G_RecvMessThread : public G_Thread
{
    public:
        /// @brief 构造函数
        G_RecvMessThread(G_ThreadPool *pool);
        /// @brief 析构函数
        ~G_RecvMessThread();
        /// @brief 主线程运行
        void Run();
        /// @brief 填加套接字
        ///
        /// @param nSocket 套接字
        void addSocket(int nSocket);
        /// @brief 获得连接的客户端数目
        ///
        /// @return 数目
        unsigned int getCounter();
        /// @brief      往队列中存放数据 ,,哪个队列?下面定义了一个queue
        ///
        /// @param pStr  数据
        ///
        /// @return true 成功 , false 失败
        bool pushData(std::string pStr);
    private:
                  
        /// @brief 设置套接口非阻塞模式
        ///
        /// @param sockfd 套接口
        ///
        /// @return true 成功 , false 失败
        bool setNonBlock(int sockfd);
        /// @brief epoll_create 返回文件描述符
        int epfd;
        struct epoll_event events[100];   //才100个。。封装了epoll啊。在recv里封了,难道send里,也封了一个
        /// @brief 记录接受客户端数目
        unsigned int counter;
        /// @brief 线程池对象
        G_ThreadPool *g_threadPool;
        /// @brief 存放数据的队列
        G_Queue<std::string> g_dataBufferQueue;
        G_Data *g_data;
};
#endif
#include "RecvMessThread.h"
#include "Log.h"
G_RecvMessThread::G_RecvMessThread(G_ThreadPool *pool) : g_threadPool(pool)
{
    counter = 0;
    epfd = epoll_create(256); //最多同时监视256个,自己又creat一个epoll
    g_data = new G_Data(this); //这个数据结构要看看,有啥稀奇
}
G_RecvMessThread::~G_RecvMessThread()
{
    close(epfd);
}
unsigned int G_RecvMessThread::getCounter()
{
    return counter;
}
bool G_RecvMessThread::setNonBlock(int sockfd)
{
    int opts = fcntl(sockfd , F_GETFL);
    if(-1 == opts)
    {
        debug_output("%s\n" , "fcntl F_GETFL is faild");
        return false;
    }
    opts = opts | O_NONBLOCK;
    if(fcntl(sockfd , F_SETFL , opts) < 0)
    {
        debug_output("%s\n" , "fcntl F_SETFL is faild");
        return false;
    }
    return true;
}
void G_RecvMessThread::addSocket(int nSocket)
{
    struct epoll_event ev;
    bzero(&ev , sizeof(ev));
    setNonBlock(nSocket);
    ev.data.fd = nSocket;
    ev.events = EPOLLIN | EPOLLET;
    epoll_ctl(epfd , EPOLL_CTL_ADD , nSocket , &ev);
    counter++;
}
bool G_RecvMessThread::pushData(std::string pStr)
{
    return g_dataBufferQueue.push(pStr);
}
void G_RecvMessThread::Run()
{
    pause();    /// 暂停线程  //都用这招。。。前面的continue,唤醒线程,具体唤醒池子里哪个线程?
    int nfds , sock;
    struct epoll_event ev;
    bool nRet;
    char line[1024]; //一次最多1024个。。感觉这个模型蛮奇怪。。
    while(1)
    {
        nfds = epoll_wait(epfd,events,100,50);
        for(int i=0; i<nfds; i++)
        {
            if(events[i].events&EPOLLIN)//监听可读事件
            {
                if((sock = events[i].data.fd) < 0)
                    continue;
                if(!(nRet=g_data->recvData(sock)))//这是最底层的收数据的啊,就是封装了recv函数。
                {
                    debug_output("client is quit\n");
                    ev.data.fd= sock;
                    epoll_ctl(epfd , EPOLL_CTL_DEL , sock , &ev);//收到了直接关掉了
                    close(sock);
                    events[i].data.fd = -1;
                    counter --;//计数的家伙。
                }
                else//收到数据
                {
                    std::string pBuffer;
                    while(g_dataBufferQueue.size())
                    {
                        g_dataBufferQueue.pop(pBuffer);//插到队列里去。这个队列是已经线程lock处理过的,哪里再去处理这个数据
                        g_threadPool->recvMessage((void*)pBuffer.c_str() , sock); //这又是一个收数据的。这个又把数据弄到哪里?
                    }
                }
                usleep(100);//还要休眠。。这么坑爹。。。这个没必要把
            }
        }
    }
}