上一节,我们学习了QTcpSocket using multiple thread ,但是我们都知道Server一般都要维持大量的connections,导致Server需要频繁的申请分配内存等资源,如果我们使用ThreadPool,一次性分配一定量的资源,这样就避免了频繁的资源申请销毁。
使用ThreadPool,我们通过查询API,要使用start()函数
void QThreadPool::start ( QRunnable * runnable, int priority = 0 )
Reserves a thread and uses it to run runnable, unless this thread will make the current thread count exceed maxThreadCount(). In that case, runnable is added to a run queue instead. The priority argument can be used to control the run queue’s order of execution.
我们的任务类要继承QRunnable,这里要声明的是QRunnable基类不是QOBject类型。它与QThread的run类似,都要实现。
void QRunnable::run () [pure virtual]
Implement this pure virtual function in your subclass.
Note that the thread pool takes ownership of the runnable if runnable->autoDelete() returns true, and the runnable will be deleted automatically by the thread pool after the runnable->run() returns. If runnable->autoDelete() returns false, ownership of runnable remains with the caller. Note that changing the auto-deletion on runnable after calling this functions results in undefined behavior.
返回过来,我们来说threadpool,如果这个线程执行完毕,那么我们可以调用autoDelete()来让pool自动销毁。
首先我们要在构造函数中设置最大连接数,setMaxThreadCount(),还有各种SLOT函数。
QThreadPool::globalIntance()->setMaxThreadCount(20);
connect(socket,SIGNAL(connected()),this,SLOT(connected())); connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected())); connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead())); socket->setSocketDescriptor(Descriptor); qDebug() << Descriptor <<"client connected"; } void Myclient::connected() { qDebug() << "client connected event"; } void Myclient::disconnected() { qDebug() << "client disconnected event"; } void Myclient::readyRead() { qDebug() << socket->readAll() ; MyTask *mytask = new MyTask(); mytask->setAutoDelete(true); connect(mytask,SIGNAL(Result(int)),this,SLOT(TaskResult(int)),Qt::QueuedConnection); QThreadPool::globalInstance()->start(mytask);//完成 Asynchronous 调用 } void Myclient::TaskResult(int Number) { QByteArray Buffer; Buffer.append("\r\nTask Result = "); Buffer.append(QString::number(Number)); socket->write(Buffer); }
这里要说明一下因为我们在线程池中另开了一个线程执行Task,所以,这个Task向Myclient发消息,属于跨线程发送消息,所以使用Qt::QueuedConnection,如果是同一个线程内的消息发送,直接Qt::DirectConnection就好。这个很重要!!!!!!
其中MyTask *mytask = new MyTask();是QRunnable类型,除此之外要使用Qt的信号与connect(),所以也要多重继承QObjec,并加入Q_OBJECT宏。这样才能引入signals与slots。
QRunnable 不继承自 QObject,故要在其中实现信号插槽,需要自行继承QObject,并添加Q_OBJCECT宏。 由此产生一个比较麻烦的事情:QRunnable线程中抛出的信号,用缺省的connectionType无法触发slot。经我的反复测试,使用Qt::DirectConnection可以触发slot,但要注意这时slot是在线程中执行的。这里有个小技巧,在slot中再次抛出信号,则其它用缺省方式connect这个信号的slot就又回到了原来的(slot本来所在的)线程。
class MyTask : public QObject , public QRunnable { Q_OBJECT public: MyTask(); protected: void run(); signals: void Result(int Number); };
然后我们在这个run()中实现我们的Task函数,这样我们就实现了Asynchronous QTcpServer。我们可以再Task中完成各种费时操作。