由于某些特殊原因,我们有时候使用线程需要QThread(信号-槽机制)。但是QThread需要继承它然后重写run函数,假如我们需要在线程中干100件事,那么就需要写100个QThread的子类,然后单独实现run函数,这样过于复杂。为此我想到使用std::function<>和模板来减少代码,写一个通用的模板线程。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #ifndef WORKERTHREADTEMPLATE_H_H #define WORKERTHREADTEMPLATE_H_H
#include <QThread> #include <functional> using namespace std; template <typename T,typename T1> class WorkerThread :public QThread { public: WorkerThread(QObject *parent = nullptr) : QThread(parent) {
}
void work( function<T (T1)> func,T1 arg) { m_Function=func; m_arg=arg; start(); }
T result(){return _result;} protected: virtual void run() {
_result =m_Function(m_arg);
} private: T1 m_arg; function<T (T1)> m_Function; T _result; }; #endif
|
这个模板只适用于一个参数的的非void返回类型,具体使用例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <QCoreApplication> #include "workerthreadtemplate.h" #include <QDebug> static bool exitFlag=true; bool myPrintf(QString str) { while(exitFlag){ qDebug()<<str; QThread::sleep(2); } return true;
} int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); WorkerThread<bool ,QString> workerThread; workerThread.work(myPrintf,QString("测试")); return a.exec(); }
|
如果传入的是类的成员非静态函数,那么需要使用std::bind。由于上述是模板类,使用起来局限性很大,无法传入任意个参数的函数。下面是改进版,使用std::bind和std::forward结合,std::bind可以简单理解为把一个函数指针和参数绑定起来,返回一个函数类型对象(std::function),参数第一个为要调用的函数指针。std::forward是保持参数传递过程中左右值属性不变。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <QThread> #include <functional>
typedef std::function<void()> Functor;
class WorkerThread :public QThread { public: explicit WorkerThread(QObject *parent = nullptr) : QThread(parent) {
} virtual ~WorkerThread(){}
template <typename T,typename... Args> void work(T func, Args... args){
m_function = std::bind(std::forward<T>(func), std::forward<Args>(args)...);
start(); }
protected: virtual void run() {
m_function(); exec();
} private: Functor m_function;
};
|
用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static bool exitFlag=true; bool myPrintf(QString str,int size) { while(exitFlag){ qDebug()<<str<<size; QThread::sleep(2); } return true; } int main() { WorkerThread *pWorkerThread=new WorkerThread(); pWorkerThread->work(myprintf,QString("test"),4); }
|