使用QTcpServer创建一个简单的服务器程序之二:多线程服务器(3)-线程池实现

首先是继承一个线程类,加入我们需要的一些基本信息。

class MyThread : public QThread
{
public:
    MyThread();
    ~MyThread();

    virtual void run();

    QList m_clientList;//每个线程维护的客户端列表
};

MyThread::MyThread()
{
    m_clientList.clear();
}

MyThread::~MyThread()
{

}

void MyThread::run()
{
    exec();//维持消息循环
}

//这里需要注意的是线程的run函数中需要调用exec(),用来维持这个线程的消息循环

然后就是线程池类,这里我只贴几个重要的函数

//获取拥有客户端数量最少的那个线程的指针
MyThread *MyThreadPool::PickMinThread()
{
    MyThread *pthread = nullptr;
    int min = 0;
    bool first = true;
    for(MyThread *pt : m_threadList)
    {
        int temp = pt->m_clientList.size();
        if(first || temp < min)
        {
            min = temp;
            pthread = pt;
        }
        first = false;
    }

    return pthread;
}


//把连接到服务器与客户端通信的socket分配到那个拥有客户端数量最少的线程上
MyTcpSocket *MyThreadPool::AssignClient(qintptr handle)
{
    MyThread *pthread = PickMinThread();//找到客户端数量最少的那个线程
    MyTcpSocket *pclient = new MyTcpSocket(handle);//在线程中创建的socket需要传入描述符
    pclient->moveToThread(pthread);

    //客户端----断开连接信号----线程池
    connect(pclient,&MyTcpSocket::disconnected,this,&MyThreadPool::SlotProcessDisconnect);

    //客户端----读信号----线程池
    connect(pclient,&MyTcpSocket::readyRead,this,&MyThreadPool::SlotProcessRead);

    //线程池---写信号----客户端
    connect(this,&MyThreadPool::SignalWriteData,pclient,&MyTcpSocket::SlotWriteData);

    QMutexLocker lock(&m_lock);
    pthread->m_clientList.append(pclient);//把客户端放入指定的线程中

    return pclient;
}

这里分享一个我当时写程序时遇到的一个坑,最开始设计的时候我是把放入线程池中的MyTcpSocket *pclient这个对象与MyTcpServer类进行信号和槽的连接,即用MyTcpServer类直接和线程池中的客户端进行通信。结果发现连接读信号时没有问题,但是连接写信号时就会爆出Qt多线程中经常遇到的那个经典问题,诸如:SocketNotifier: socket notifiers cannot be enabled from another thread或者是QObject: Cannot create children for a parent that is in a different thread,反正就是类似的错误。我百思不得其解,因为这是moveToThread之后必须进行的信号槽连接。后来我改用MyThreadPool类和客户端进行信号槽连接就好了。也不知道为什么,请知道原因的朋友麻烦告知详情。

你可能感兴趣的:(Qt)