move app to examples
@ -4,4 +4,6 @@ TaoQuick_BUILD_TREE = $$PWD/build
|
||||
|
||||
TaoQuick_RUN_TREE = $$PWD/bin
|
||||
|
||||
TaoQuick_3RDPARTY_TREE = $$PWD/3rdparty
|
||||
|
||||
TaoQuick_VERSION_MAJOR = 0.3
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
#include "Logger/logger.h"
|
||||
namespace TaoCommon
|
||||
{
|
||||
static bool readFile(const QString &filePath, QByteArray &content)
|
||||
@ -12,7 +13,7 @@ namespace TaoCommon
|
||||
QFile file(filePath);
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
{
|
||||
qWarning() << "open file " << filePath << "failed:" << file.errorString();
|
||||
LOG_WARN << "open file " << filePath << "failed:" << file.errorString();
|
||||
return false;
|
||||
}
|
||||
content = file.readAll();
|
||||
@ -25,7 +26,7 @@ namespace TaoCommon
|
||||
doc = QJsonDocument::fromJson(data, &err);
|
||||
if (doc.isNull())
|
||||
{
|
||||
qWarning() << "parse json failed:" << err.errorString();
|
||||
LOG_WARN << "parse json failed:" << err.errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -83,7 +84,7 @@ namespace TaoCommon
|
||||
QFile file(filePath);
|
||||
if (!file.open(QFile::WriteOnly))
|
||||
{
|
||||
qWarning() << "open file " << filePath << "failed:" << file.errorString();
|
||||
LOG_WARN << "open file " << filePath << "failed:" << file.errorString();
|
||||
return false;
|
||||
}
|
||||
file.write(content);
|
125
3rdparty/TaoCommon/Common/objectmap.h
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
namespace TaoCommon
|
||||
{
|
||||
|
||||
//对象存储器
|
||||
template <typename Key, typename Value>
|
||||
class ObjectMap
|
||||
{
|
||||
public:
|
||||
virtual ~ObjectMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
void setObj(const Key &key, const Value &obj)
|
||||
{
|
||||
m_objMap[key] = obj;
|
||||
}
|
||||
Value getObj(const Key &key) const
|
||||
{
|
||||
auto itor = m_objMap.find(key);
|
||||
if (itor == m_objMap.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return itor->second;
|
||||
}
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
m_objMap.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unordered_map<Key, Value> m_objMap;
|
||||
};
|
||||
//智能对象存储器。自动生成key,自动管理对象。
|
||||
template <typename ObjectType>
|
||||
class CObjectMap : public ObjectMap<std::type_index, std::shared_ptr<ObjectType>>
|
||||
{
|
||||
public:
|
||||
template <typename DeriveObjectType>
|
||||
DeriveObjectType *getObject() const
|
||||
{
|
||||
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
|
||||
auto objPtr = getObj(std::type_index(typeid(std::shared_ptr<DeriveObjectType>)));
|
||||
return std::static_pointer_cast<DeriveObjectType>(objPtr).get();
|
||||
}
|
||||
template <typename DeriveObjectType, typename... Args>
|
||||
void setObject(Args &&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
|
||||
auto obj = std::make_shared<DeriveObjectType>(std::forward(args...));
|
||||
setObj(std::type_index(typeid(obj)), std::static_pointer_cast<ObjectType>(obj));
|
||||
}
|
||||
void forEach(const std::function<void(ObjectType *)> &callback) const
|
||||
{
|
||||
for (const auto &pair : m_objMap)
|
||||
{
|
||||
callback(pair.second.get());
|
||||
}
|
||||
}
|
||||
};
|
||||
//优先级对象存储器。自动生成key,自动管理对象。支持按优先级处理
|
||||
template <typename ObjectType>
|
||||
class CLevelObjectMap
|
||||
{
|
||||
public:
|
||||
virtual ~CLevelObjectMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
template <typename DeriveObjectType>
|
||||
DeriveObjectType *getObject() const
|
||||
{
|
||||
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
|
||||
auto index = std::type_index(typeid(std::shared_ptr<DeriveObjectType>));
|
||||
|
||||
for (const auto &mainPair : m_map)
|
||||
{
|
||||
const std::unordered_map<std::type_index, std::shared_ptr<ObjectType>> &subMap = mainPair.second;
|
||||
|
||||
auto itor = subMap.find(index);
|
||||
if (itor != subMap.end())
|
||||
{
|
||||
return std::static_pointer_cast<DeriveObjectType>(itor->second).get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
template <typename DeriveObjectType, typename... Args>
|
||||
void setObject(uint32_t level, Args &&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<ObjectType, DeriveObjectType>::value, "DeriveObjectType must be derive from ObjectType");
|
||||
auto obj = std::make_shared<DeriveObjectType>(args...);
|
||||
m_map[level][std::type_index(typeid(obj))] = std::static_pointer_cast<ObjectType>(obj);
|
||||
}
|
||||
void forEach(const std::function<void(ObjectType *)> &callback) const
|
||||
{
|
||||
for (const auto &mainPair : m_map)
|
||||
{
|
||||
const std::unordered_map<std::type_index, std::shared_ptr<ObjectType>> &subMap = mainPair.second;
|
||||
for (const auto &subPair : subMap)
|
||||
{
|
||||
callback(subPair.second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
m_map.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<uint32_t, std::unordered_map<std::type_index, std::shared_ptr<ObjectType>>> m_map;
|
||||
};
|
||||
} // namespace TaoCommon
|
42
3rdparty/TaoCommon/Common/singleton.h
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
namespace TaoCommon
|
||||
{
|
||||
//单例模板
|
||||
template <typename T>
|
||||
class Singleton
|
||||
{
|
||||
public:
|
||||
static T &instance()
|
||||
{
|
||||
static T t;
|
||||
return t;
|
||||
}
|
||||
virtual ~Singleton() {}
|
||||
|
||||
Singleton(const Singleton &) = delete;
|
||||
Singleton &operator=(const Singleton &) = delete;
|
||||
|
||||
protected:
|
||||
Singleton() {}
|
||||
};
|
||||
/*
|
||||
使用示例:
|
||||
|
||||
定义:
|
||||
class DataManager : public Singleton<DataManager>
|
||||
{
|
||||
friend class Singleton<DataManager>;
|
||||
public:
|
||||
void loadData();
|
||||
protected:
|
||||
DataManager();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
调用:
|
||||
DataManager::instance().loadData();
|
||||
*/
|
||||
|
||||
} // namespace TaoCommon
|
116
3rdparty/TaoCommon/Common/subject.h
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
namespace TaoCommon
|
||||
{
|
||||
//观察者模式,Subject-Observer。
|
||||
//Subject 事件或消息的主体。模板参数为观察者类型
|
||||
template <typename ObserverType>
|
||||
class Subject
|
||||
{
|
||||
public:
|
||||
virtual ~Subject()
|
||||
{
|
||||
m_obsList.clear();
|
||||
}
|
||||
//订阅
|
||||
void subscibe(ObserverType *obs)
|
||||
{
|
||||
auto itor = std::find(m_obsList.begin(), m_obsList.end(), obs);
|
||||
if (m_obsList.end() == itor)
|
||||
{
|
||||
m_obsList.push_back(obs);
|
||||
}
|
||||
}
|
||||
//取消订阅
|
||||
void unSubscibe(ObserverType *obs)
|
||||
{
|
||||
m_obsList.erase(std::remove(m_obsList.begin(), m_obsList.end(), obs));
|
||||
}
|
||||
//发布。这里的模板参数为函数类型。
|
||||
template <typename FuncType>
|
||||
void publish(FuncType func)
|
||||
{
|
||||
for (auto obs : m_obsList)
|
||||
{
|
||||
//调用回调函数,将obs作为第一个参数传递
|
||||
func(obs);
|
||||
}
|
||||
}
|
||||
//发布。支持过滤观察者。通常用在 观察者触发消息发布时,过滤观察者自己。
|
||||
template <typename FuncType>
|
||||
void publish(FuncType func, ObserverType *exceptObs)
|
||||
{
|
||||
for (auto obs : m_obsList)
|
||||
{
|
||||
//调用回调函数,将obs作为第一个参数传递
|
||||
if (obs != exceptObs)
|
||||
{
|
||||
func(obs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ObserverType *> m_obsList;
|
||||
};
|
||||
|
||||
//优先级观察者模式,Subject-Observer。
|
||||
template <typename ObserverType>
|
||||
class LevelSubject
|
||||
{
|
||||
public:
|
||||
virtual ~LevelSubject()
|
||||
{
|
||||
m_obsMap.clear();
|
||||
}
|
||||
//订阅
|
||||
void subscibe(ObserverType *obs, uint32_t level)
|
||||
{
|
||||
auto &vec = m_obsMap[level];
|
||||
auto itor = std::find(vec.begin(), vec.end(), obs);
|
||||
if (vec.end() == itor)
|
||||
{
|
||||
vec.push_back(obs);
|
||||
}
|
||||
}
|
||||
//取消订阅
|
||||
void unSubscibe(ObserverType *obs)
|
||||
{
|
||||
for (auto &obsPair : m_obsMap)
|
||||
{
|
||||
obsPair.second.erase(std::remove(obsPair.second.begin(), obsPair.second.end(), obs));
|
||||
}
|
||||
}
|
||||
//发布。这里的模板参数为函数类型。
|
||||
template <typename FuncType>
|
||||
void publish(FuncType func)
|
||||
{
|
||||
for (const auto &obsPair : m_obsMap)
|
||||
{
|
||||
for (const auto &obs : obsPair.second)
|
||||
{
|
||||
func(obs);
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename FuncType>
|
||||
void publish(FuncType func, ObserverType *exceptObs)
|
||||
{
|
||||
for (const auto &obsPair : m_obsMap)
|
||||
{
|
||||
for (const auto &obs : obsPair.second)
|
||||
{
|
||||
if (obs != exceptObs)
|
||||
{
|
||||
func(obs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<uint32_t, std::vector<ObserverType *>> m_obsMap;
|
||||
};
|
||||
} // namespace TaoCommon
|
145
3rdparty/TaoCommon/Logger/logger.cpp
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
#include "logger.h"
|
||||
#include "loggertemplate.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QMutex>
|
||||
#include <QDebug>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
namespace Logger
|
||||
{
|
||||
static QString gLogDir;
|
||||
static int gLogMaxCount;
|
||||
|
||||
static void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
static void outputMessageAsync(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
|
||||
void initLog(const QString &logPath, int logMaxCount, bool async)
|
||||
{
|
||||
if (async)
|
||||
{
|
||||
qInstallMessageHandler(outputMessageAsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
qInstallMessageHandler(outputMessage);
|
||||
}
|
||||
|
||||
gLogDir = QCoreApplication::applicationDirPath() + QStringLiteral("/") + logPath;
|
||||
gLogMaxCount = logMaxCount;
|
||||
QDir dir(gLogDir);
|
||||
if (!dir.exists())
|
||||
{
|
||||
dir.mkpath(dir.absolutePath());
|
||||
}
|
||||
QStringList infoList = dir.entryList(QDir::Files, QDir::Name);
|
||||
while (infoList.size() > gLogMaxCount)
|
||||
{
|
||||
dir.remove(infoList.first());
|
||||
infoList.removeFirst();
|
||||
}
|
||||
}
|
||||
static void outputMessageAsync(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
{
|
||||
static const QString messageTemp = QStringLiteral("<div class=\"%1\">%2</div>\r\n");
|
||||
static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' };
|
||||
static QMutex mutex;
|
||||
static QFile file;
|
||||
static QTextStream textStream;
|
||||
static uint count = 0;
|
||||
static const uint maxCount = 512;
|
||||
Q_UNUSED(context)
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
|
||||
//每小时一个文件
|
||||
QString fileNameDt = dt.toString(QStringLiteral("yyyy-MM-dd_hh"));
|
||||
|
||||
//每分钟一个文件
|
||||
//QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm");
|
||||
|
||||
QString contentDt = dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
|
||||
QString message = QStringLiteral("%1 %2").arg(contentDt).arg(msg);
|
||||
QString htmlMessage = messageTemp.arg(typeList[static_cast<int>(type)]).arg(message);
|
||||
QString newfileName = QStringLiteral("%1/%2_log.html").arg(gLogDir).arg(fileNameDt);
|
||||
mutex.lock();
|
||||
if (file.fileName() != newfileName)
|
||||
{
|
||||
if (file.isOpen())
|
||||
{
|
||||
file.close();
|
||||
}
|
||||
file.setFileName(newfileName);
|
||||
bool exist = file.exists();
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
textStream.setDevice(&file);
|
||||
textStream.setCodec("UTF-8");
|
||||
if (!exist)
|
||||
{
|
||||
textStream << logTemplate << "\r\n";
|
||||
}
|
||||
}
|
||||
textStream << htmlMessage;
|
||||
textStream.flush();
|
||||
count += htmlMessage.length();
|
||||
if (count >= maxCount)
|
||||
{
|
||||
file.close();
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
}
|
||||
mutex.unlock();
|
||||
#ifdef Q_OS_WIN
|
||||
::OutputDebugString(message.toStdWString().data());
|
||||
::OutputDebugString(L"\r\n");
|
||||
#else
|
||||
fprintf(stderr, message.toStdString().data());
|
||||
#endif
|
||||
}
|
||||
static void outputMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
||||
{
|
||||
static const QString messageTemp = QStringLiteral("<div class=\"%1\">%2</div>\r\n");
|
||||
static const char typeList[] = { 'd', 'w', 'c', 'f', 'i' };
|
||||
static QMutex mutex;
|
||||
|
||||
Q_UNUSED(context)
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
|
||||
//每小时一个文件
|
||||
QString fileNameDt = dt.toString(QStringLiteral("yyyy-MM-dd_hh"));
|
||||
|
||||
//每分钟一个文件
|
||||
//QString fileNameDt = dt.toString("yyyy-MM-dd_hh_mm");
|
||||
|
||||
QString contentDt = dt.toString(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
|
||||
QString message = QStringLiteral("%1 %2").arg(contentDt).arg(msg);
|
||||
QString htmlMessage = messageTemp.arg(typeList[static_cast<int>(type)]).arg(message);
|
||||
QFile file(QStringLiteral("%1/%2_log.html").arg(gLogDir).arg(fileNameDt));
|
||||
mutex.lock();
|
||||
|
||||
bool exist = file.exists();
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
QTextStream textStream(&file);
|
||||
textStream.setCodec("UTF-8");
|
||||
if (!exist)
|
||||
{
|
||||
textStream << logTemplate << "\r\n";
|
||||
}
|
||||
textStream << htmlMessage;
|
||||
file.close();
|
||||
mutex.unlock();
|
||||
#ifdef Q_OS_WIN
|
||||
::OutputDebugString(message.toStdWString().data());
|
||||
::OutputDebugString(L"\r\n");
|
||||
#else
|
||||
fprintf(stderr, message.toStdString().data());
|
||||
#endif
|
||||
}
|
||||
} // namespace Logger
|
23
3rdparty/TaoCommon/Logger/logger.h
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "taocommonglobal.h"
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
namespace Logger
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#define LOG_DEBUG qDebug() << __FILE__ << __LINE__
|
||||
#define LOG_INFO qInfo() << __FILE__ << __LINE__
|
||||
#define LOG_WARN qWarning() << __FILE__ << __LINE__
|
||||
#define LOG_CRIT qCritical() << __FILE__ << __LINE__
|
||||
#else
|
||||
#define LOG_DEBUG qDebug()
|
||||
#define LOG_INFO qInfo()
|
||||
#define LOG_WARN qWarning()
|
||||
#define LOG_CRIT qCritical()
|
||||
#endif
|
||||
// 初始化Log存储。包括创建Log文件夹、删除超过最大数的log(仅初始化时删除,运行过程中不删除)。
|
||||
// logPath 存储路径
|
||||
// logMaxCount 最大数
|
||||
// async 是否异步存储 默认异步存储。异步存储会缓存log,达到一定数量、或者软件退出时才写入文件。
|
||||
void TAO_API initLog(const QString &logPath = QStringLiteral("Log"), int logMaxCount = 1024, bool async = true);
|
||||
} // namespace Logger
|
@ -3,13 +3,13 @@
|
||||
#include <string>
|
||||
namespace Logger
|
||||
{
|
||||
const static QString logTemplate = u8R"logTemplate(
|
||||
const static auto logTemplate = QString::fromUtf8(u8R"logTemplate(
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>TaoLogger</title>
|
||||
<title>Lubansoft log file</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style type="text/css" id="logCss">
|
||||
body {
|
||||
@ -86,7 +86,7 @@ namespace Logger
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1><a href="https://jaredtao.github.io">TaoLogger</a> 日志文件</h1>
|
||||
<h1><a href="http://jaredtao.github.io/">TaoLogger</a> 日志文件</h1>
|
||||
<script type="text/JavaScript">
|
||||
function objHide(obj) {
|
||||
obj.style.display="none"
|
||||
@ -122,5 +122,5 @@ namespace Logger
|
||||
<option value='c'>Critical</option>
|
||||
<option value='f'>Fatal</option>
|
||||
</select>
|
||||
)logTemplate";
|
||||
)logTemplate");
|
||||
}
|
25
3rdparty/TaoCommon/TaoCommon.pri
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
!build_TaoCommon_lib:{
|
||||
DEFINES +=TaoCommon_NO_LIB
|
||||
}
|
||||
|
||||
INCLUDEPATH += $$PWD \
|
||||
$$PWD/Common \
|
||||
$$PWD/Logger \
|
||||
$$PWD/Thread
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/Common/filereadwrite.h \
|
||||
$$PWD/Common/objectmap.h \
|
||||
$$PWD/Common/singleton.h \
|
||||
$$PWD/Common/subject.h \
|
||||
$$PWD/Logger/loggertemplate.h \
|
||||
$$PWD/Logger/logger.h \
|
||||
$$PWD/Thread/threadcommon.h \
|
||||
$$PWD/Thread/threadpool.h \
|
||||
$$PWD/Thread/threadworkercontroller.h \
|
||||
$$PWD/taocommonglobal.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/Logger/logger.cpp \
|
||||
$$PWD/Thread/threadpool.cpp
|
||||
|
14
3rdparty/TaoCommon/TaoCommon.pro
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
TARGET = TaoCommon
|
||||
|
||||
load(qt_module)
|
||||
|
||||
QT += core
|
||||
QMAKE_TARGET_COMPANY = "jaredtao.github.io"
|
||||
QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2019-2022 JaredTao <jared2020@163.com>"
|
||||
QMAKE_TARGET_PRODUCT = "TaoCommon"
|
||||
QMAKE_TARGET_DESCRIPTION = "common use code for Qt."
|
||||
|
||||
CONFIG += build_TaoCommon_lib
|
||||
DEFINES += TaoCommon_Library
|
||||
|
||||
include(TaoCommon.pri)
|
10
3rdparty/TaoCommon/Thread/threadcommon.h
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <QMetaType>
|
||||
#include <functional>
|
||||
namespace TaoCommon
|
||||
{
|
||||
using WorkCallback = std::function<bool()>;
|
||||
using WorkResultCallback = std::function<void(bool)>;
|
||||
}
|
||||
Q_DECLARE_METATYPE(TaoCommon::WorkCallback);
|
||||
Q_DECLARE_METATYPE(TaoCommon::WorkResultCallback);
|
22
3rdparty/TaoCommon/Thread/threadpool.cpp
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
#include "threadpool.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
namespace TaoCommon
|
||||
{
|
||||
ThreadObject::ThreadObject(const WorkCallback& work) : m_workCall(work) {}
|
||||
void ThreadObject::run()
|
||||
{
|
||||
bool ok = m_workCall();
|
||||
emit readyResult(ok);
|
||||
}
|
||||
//workCall in sub thread, resultCall in main thread
|
||||
void ThreadPool::work(const WorkCallback& workCall, const WorkResultCallback& resultCall)
|
||||
{
|
||||
ThreadObject* obj = new ThreadObject(workCall);
|
||||
obj->setAutoDelete(true);
|
||||
connect(obj, &ThreadObject::readyResult, this, resultCall);
|
||||
QThreadPool::globalInstance()->start(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
41
3rdparty/TaoCommon/Thread/threadpool.h
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "taocommonglobal.h"
|
||||
#include "threadcommon.h"
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
namespace TaoCommon
|
||||
{
|
||||
// 对Qt线程池的简单封装,适合一次性执行的任务。
|
||||
// 用法: ThreadPool::getInstance()->work(workCall, resultCall)
|
||||
// workCall是在新线程中执行的任务,resultCall是任务执行完成后,回到调用线程中用来处理执行结果。
|
||||
// 不支持任务取消、暂停。
|
||||
|
||||
class ThreadObject
|
||||
: public QObject
|
||||
, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThreadObject(const WorkCallback& work);
|
||||
void run() override;
|
||||
signals:
|
||||
void readyResult(bool);
|
||||
|
||||
private:
|
||||
WorkCallback m_workCall;
|
||||
};
|
||||
class TAO_API ThreadPool : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ThreadPool* getInstance()
|
||||
{
|
||||
static ThreadPool poll;
|
||||
return &poll;
|
||||
}
|
||||
//workCall in sub thread, resultCall in main thread
|
||||
void work(const WorkCallback& workCall, const WorkResultCallback& resultCall);
|
||||
private:
|
||||
ThreadPool() {}
|
||||
};
|
||||
} // namespace TaoCommon
|
129
3rdparty/TaoCommon/Thread/threadworkercontroller.h
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#include "taocommonglobal.h"
|
||||
#include "threadcommon.h"
|
||||
#include <QMap>
|
||||
#include <QThread>
|
||||
namespace TaoCommon
|
||||
{
|
||||
// 对Qt Worker-Controller 线程模型的简单封装,适合精确控制的任务。
|
||||
// 用法: ThreadController::getInstance()->work(workCall, resultCall)
|
||||
// workCall是在新线程中执行的任务,resultCall是任务执行完成后,回到调用线程中用来处理执行结果。
|
||||
// work函数返回值为任务id。
|
||||
// 取消任务用ThreadController::getInstance()->cancle(id)函数。
|
||||
class ThreadWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ThreadWorker(uint64_t id, const WorkCallback &workCall, QObject *parent = nullptr) : QObject(parent), m_id(id), m_workCall(workCall) {}
|
||||
|
||||
signals:
|
||||
void workFinished(bool, uint64_t);
|
||||
public slots:
|
||||
void doWork()
|
||||
{
|
||||
bool ret = m_workCall();
|
||||
emit workFinished(ret, m_id);
|
||||
}
|
||||
private:
|
||||
const uint64_t m_id;
|
||||
WorkCallback m_workCall;
|
||||
};
|
||||
class TAO_API ThreadController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static ThreadController *getInstance()
|
||||
{
|
||||
static ThreadController controller;
|
||||
return &controller;
|
||||
}
|
||||
|
||||
~ThreadController()
|
||||
{
|
||||
for (auto k : m_threadMap.uniqueKeys())
|
||||
{
|
||||
if (m_threadMap.value(k)->isRunning())
|
||||
{
|
||||
m_threadMap.value(k)->quit();
|
||||
m_threadMap.value(k)->wait();
|
||||
}
|
||||
}
|
||||
qDeleteAll(m_threadMap);
|
||||
m_threadMap.clear();
|
||||
m_resultCallback.clear();
|
||||
}
|
||||
uint64_t work(const WorkCallback &workCall, const WorkResultCallback &resultCall)
|
||||
{
|
||||
QThread *thread = new QThread;
|
||||
m_rollId++;
|
||||
ThreadWorker *obj = new ThreadWorker(m_rollId, workCall);
|
||||
m_threadMap[m_rollId] = thread;
|
||||
m_resultCallback[m_rollId] = resultCall;
|
||||
obj->moveToThread(thread);
|
||||
|
||||
connect(thread, &QThread::finished, obj, &QObject::deleteLater);
|
||||
connect(thread, &QThread::started, obj, &ThreadWorker::doWork);
|
||||
connect(obj, &ThreadWorker::workFinished, this, &ThreadController::onWorkFinished, Qt::QueuedConnection);
|
||||
thread->start();
|
||||
return m_rollId;
|
||||
}
|
||||
void cancle(uint64_t id)
|
||||
{
|
||||
auto it = m_threadMap.find(id);
|
||||
if (it != m_threadMap.end())
|
||||
{
|
||||
if ((*it)->isRunning())
|
||||
{
|
||||
(*it)->terminate();
|
||||
}
|
||||
}
|
||||
m_resultCallback.remove(id);
|
||||
}
|
||||
void quit(uint64_t id)
|
||||
{
|
||||
auto it = m_threadMap.find(id);
|
||||
if (it != m_threadMap.end())
|
||||
{
|
||||
if ((*it)->isRunning())
|
||||
{
|
||||
(*it)->quit();
|
||||
(*it)->wait();
|
||||
(*it)->deleteLater();
|
||||
}
|
||||
}
|
||||
m_resultCallback.remove(id);
|
||||
}
|
||||
QList<uint64_t> getAllWorkId() const
|
||||
{
|
||||
return m_threadMap.uniqueKeys();
|
||||
}
|
||||
protected slots :
|
||||
void onWorkFinished(bool ok, uint64_t id)
|
||||
{
|
||||
auto it = m_threadMap.find(id);
|
||||
if (it != m_threadMap.end())
|
||||
{
|
||||
if ((*it)->isRunning())
|
||||
{
|
||||
(*it)->quit();
|
||||
(*it)->wait();
|
||||
(*it)->deleteLater();
|
||||
}
|
||||
m_threadMap.remove(id);
|
||||
}
|
||||
auto caller = m_resultCallback.find(id);
|
||||
if (caller != m_resultCallback.end())
|
||||
{
|
||||
(*caller)(ok);
|
||||
m_resultCallback.remove(id);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
ThreadController(QObject *parent = nullptr) : QObject(parent) {}
|
||||
|
||||
private:
|
||||
uint64_t m_rollId = 0;
|
||||
QMap<uint64_t, QThread *> m_threadMap;
|
||||
QMap<uint64_t, WorkResultCallback> m_resultCallback;
|
||||
};
|
||||
} // namespace LCIM
|
12
3rdparty/TaoCommon/taocommonglobal.h
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#if !defined(BUILD_STATIC) && !defined(TaoCommon_NO_LIB)
|
||||
#if defined(TaoCommon_Library)
|
||||
#define TAO_API Q_DECL_EXPORT
|
||||
#else
|
||||
#define TAO_API Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define TAO_API
|
||||
#endif
|
@ -7,7 +7,9 @@ lessThan(QT_MAJOR_VERSION, 5) {
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += \
|
||||
src
|
||||
src \
|
||||
examples
|
||||
CONFIG+= ordered
|
||||
|
||||
OTHER_FILES += *.md \
|
||||
LICENSE \
|
||||
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 833 B After Width: | Height: | Size: 833 B |
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 870 B |
Before Width: | Height: | Size: 447 B After Width: | Height: | Size: 447 B |
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 410 B |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 972 B After Width: | Height: | Size: 972 B |
Before Width: | Height: | Size: 260 B After Width: | Height: | Size: 260 B |
Before Width: | Height: | Size: 239 B After Width: | Height: | Size: 239 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 528 B After Width: | Height: | Size: 528 B |
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 981 B After Width: | Height: | Size: 981 B |
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 217 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 180 B |