这两个线程的实现,是被QT开发者骂的实现,虽然是没有什么问题,可是总感觉怪怪的,因此,我外部客户端用了QT开发者推荐的做法moveToThread,开始前总结两个线程之前,先稍微总结一下QThread的用法吧:
1. 是我这两个线程实现的做法,继承QThread,重载run函数,在run中做while(true)的循环,设置跳出循环标志位,然后在while循环中进行操作。
2. 是我外部控制用的做法,继承QObject类,将该类moveToThread(QThread *),然后要放入线程的操作写在槽函数中,每次通过信号槽来触发线程进行操作,通过回调函数或是信号槽来返回处理结果给外部。这样使用起来很方便,并且不用担心程序关闭时,线程还没完全退出的问题。
CommandThread的实现
主要的功能在于将异步转同步的问题,由于和相机交互一定是一去一回的交互方式,应该等到上一个命令响应成功以后,再发送下一个命令,但由于http的通讯是异步的,因此,线程需要一个队列保存待处理的命令请求,每当相机返回命令的响应的以后,去检查队列是否有待处理的命令,如果有则继续发送,否则阻塞自己,直到有新命令入队列将其唤醒。在新命令来的时候,如果队列已经有待处理的命令,或是目前正在等待最后一个命令的相应的话,就需要入队,否则说明命令线程处于阻塞状态,将命令入队并唤醒线程。
CommandThread.h:
#ifndef COMMANDTHREAD_H
#define COMMANDTHREAD_H
#include <QThread>
#include <QQueue>
#include <QWaitCondition>
#include <QMutex>
#include "httpexecutor.h"
/*Error code*/
#define Command_Response_Error 0x2007
namespace xfhttpcamera {
class CommandThreadCallback
{
public:
CommandThreadCallback() {}
virtual void commandError(HttpExecutor *exec, QString error, int errorCode){
Q_UNUSED(exec);
Q_UNUSED(error);
Q_UNUSED(errorCode);
throw std::runtime_error("un-implement.");
}
virtual void commandSuccess(HttpExecutor *exec) {
Q_UNUSED(exec);
throw std::runtime_error("un-implement.");
}
virtual void executeCommandData(HttpExecutor *exec, QVariant &data) {
Q_UNUSED(exec);
Q_UNUSED(data);
throw std::runtime_error("un-implement.");
}
};
class CommandThread : public QThread, public HttpExecutorCallback
{
Q_OBJECT
public:
CommandThread(QNetworkAccessManager *manager, QObject *paren = 0);
void enqueue(HttpExecutor *exec);
virtual void responseError(ResponseException &exception);
virtual void response();
virtual void responseData(QVariant &data);
void setCallback(CommandThreadCallback *callback);
signals:
void newCommandEnqueue();
private slots:
void executeNewCommand();
private:
QNetworkAccessManager *_manager;
CommandThreadCallback *_callback;
QQueue<HttpExecutor *> _commandQueue;
QWaitCondition _commandWaitCondition;
QMutex _mutex;
friend class HttpSonyCamera;
};
}
#endif // COMMANDTHREAD_H
CommandThread.cpp:
#include "commandthread.h"
namespace xfhttpcamera {
CommandThread::CommandThread(QNetworkAccessManager *manager, QObject *paren):
QThread(paren)
{
_manager = manager;
connect(this, &CommandThread::newCommandEnqueue, this, &CommandThread::executeNewCommand, Qt::ConnectionType::QueuedConnection);
}
void CommandThread::enqueue(HttpExecutor *exec)
{
QMutexLocker locker(&_mutex);
_commandWaitCondition.wakeOne();
exec->moveToThread(this);
if(_commandQueue.isEmpty()){
_commandQueue.enqueue(exec);
emit newCommandEnqueue();
}else
_commandQueue.enqueue(exec);
}
void CommandThread::responseError(ResponseException &exception)
{
QString err = "Error code:" + QString::number(exception.code,16) + " Error message:" + exception.message;
HttpExecutor *exec = _commandQueue.dequeue();
_callback->commandError(exec, err, Command_Response_Error);
}
void CommandThread::response()
{
QMutexLocker locker(&_mutex);
HttpExecutor *exec = _commandQueue.dequeue();
_callback->commandSuccess(exec);
if(_commandQueue.isEmpty())
_commandWaitCondition.wait(&_mutex);
else{
HttpExecutor *nextExec = _commandQueue.head();
nextExec->setCallback(this);
nextExec->execute(_manager);
}
}
void CommandThread::responseData(QVariant &data)
{
HttpExecutor *exec = _commandQueue.head();
_callback->executeCommandData(exec, data);
}
void CommandThread::setCallback(CommandThreadCallback *callback)
{
_callback = callback;
}
void CommandThread::executeNewCommand()
{
qDebug() << "command thread:" << QThread::currentThreadId();
HttpExecutor *nextExec = _commandQueue.head();
nextExec->setCallback(this);
nextExec->execute(_manager);
}
}
GetLiveViewStreamThread实现
这里就是去不断处理get返回回来的数据,没有什么好说的,直接上代码。
GetLiveViewStreamThread.h:
#ifndef GETLIVEVIEWSTREAMTHREAD_H
#define GETLIVEVIEWSTREAMTHREAD_H
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include "getliveviewstreamexecutor.h"
/*Error code*/
#define Get_Live_View_Response_Error 0x2006
namespace xfhttpcamera {
class GetLiveViewStreamThreadCallback
{
public:
GetLiveViewStreamThreadCallback() {}
virtual void liveViewError(sonyrx::GetLiveViewStreamExecutor *exec, QString error, int errorCode){
Q_UNUSED(exec);
Q_UNUSED(error);
Q_UNUSED(errorCode);
throw std::runtime_error("un-implement.");
}
virtual void liveViewStopped(sonyrx::GetLiveViewStreamExecutor *exec) {
Q_UNUSED(exec);
throw std::runtime_error("un-implement.");
}
virtual void liveViewDataGet(QByteArray &data) {
Q_UNUSED(data);
throw std::runtime_error("un-implement.");
}
};
class GetLiveViewStreamThread : public QThread, public HttpExecutorCallback
{
Q_OBJECT
public:
GetLiveViewStreamThread(sonyrx::GetLiveViewStreamExecutor *exec, QNetworkAccessManager *manager, QObject *parent = 0);
virtual void responseError(ResponseException &exception);
virtual void response();
virtual void responseData(QVariant &data);
void setCallback(GetLiveViewStreamThreadCallback *callback);
sonyrx::GetLiveViewStreamExecutor *liveViewExecutor(){return _exec;}
protected:
void run();
private:
sonyrx::GetLiveViewStreamExecutor *_exec;
QNetworkAccessManager *_manager;
GetLiveViewStreamThreadCallback *_callback;
};
}
#endif // GETLIVEVIEWSTREAMTHREAD_H
GetLiveViewStreamThread.cpp:
#include "getliveviewstreamthread.h"
namespace xfhttpcamera {
GetLiveViewStreamThread::GetLiveViewStreamThread(sonyrx::GetLiveViewStreamExecutor *exec, QNetworkAccessManager *manager, QObject *parent):
QThread(parent)
{
exec->moveToThread(this);
_exec = exec;
_manager = manager;
}
void GetLiveViewStreamThread::responseError(ResponseException &exception)
{
QString err = "Error code:" + QString::number(exception.code,16) + " Error message:" + exception.message;
_callback->liveViewError(_exec, err, Get_Live_View_Response_Error);
}
void GetLiveViewStreamThread::response()
{
_callback->liveViewStopped(_exec);
}
void GetLiveViewStreamThread::responseData(QVariant &data)
{
QByteArray imageData = data.toByteArray();
_callback->liveViewDataGet(imageData);
}
void GetLiveViewStreamThread::setCallback(GetLiveViewStreamThreadCallback *callback)
{
_callback = callback;
}
void GetLiveViewStreamThread::run()
{
_exec->setCallback(this);
_exec->execute(_manager);
exec();
}
}