插件算法管理以及任务队列机制

插件管理

插件管理者执行构造函数的时候,加载所有插件实例,每一个插件实例在构造的时候加载它的插件,外部使用者通过插件管理者的QMap获得想要的插件,可以通过得到插件的具体算法。
在这里插入图片描述

抽象插件基类

抽象插件基类,给出基本的接口。

#ifndef ABSTRACTPLUGIN_H
#define ABSTRACTPLUGIN_H

class AbstractPlugin {
public:
    AbstractPlugin() = default;
    virtual ~AbstractPlugin() = default;
    virtual bool start(const char*) = 0;
    virtual bool stop() = 0;
    virtual double progress() = 0;
};

#endif // ABSTRACTPLUGIN_H

插件导入导出规范

利用了工厂设计模式,注册插件的时候导出具体插件类,加载的时候也可以得到具体插件类。

#define PLUGIN(classType, pluginName, pluginVersion) \
    extern "C" {                                     \
        __attribute__ ((visibility ("default"))) AbstractPlugin* createPlugin() {             \
            return new classType();                  \
        }                                            \
        __attribute__ ((visibility ("default"))) Plugin exports = {                           \
            pluginName,                              \
            pluginVersion,                           \
            createPlugin,                            \
        };                                           \
    }
#endif //C3PTEMPLATE_PLUGIN_H

attribute((visibility(“default”)))

__attribute__((visibility("default")))  //默认,设置为:default之后就可以让外面的类看见了。
__attribute__((visibility("hideen")))  //隐藏

visibility用于设置动态链接库中函数的可见性,将变量或函数设置为hidden,则该符号仅在本so中可见,在其他库中则不可见。
g++在编译时,可用参数-fvisibility指定所有符号的可见性(不加此参数时默认外部可见,参考man g++中-fvisibility部分);若需要对特定函数的可见性进行设置,需在代码中使用attribute设置visibility属性。
编写大型程序时,可用-fvisibility=hidden设置符号默认隐藏,针对特定变量和函数,在代码中使用attribute ((visibility(“default”)))另该符号外部可见,这种方法可用有效避免so之间的符号冲突。

FDK插件算法编译命令:
nvcc --compiler-options "-Bsymbolic -fvisibility=hidden -fPIC " -shared -O3 -std=c++11 -Xcompiler -fopenmp *.cpp *.cu -o libFdkCuda.so

插件实例

插件实例负责加载、运行和监督插件的运行进度。

#include "PluginInstance.h"

#include <thread>

#include "tool/macroTools.h"
#include "tool/Log.h"

PluginInstance::PluginInstance(QString path) {
    mPluginPath = path;
    reload();
}

PluginInstance::~PluginInstance() {
    SAFE_DELETE(mPlugin);
    mLib.close();
    if (mPluginExport != nullptr) {
        // PluginExport has been deleted by mLib.
        Log::exec("PluginInstance::~PluginInstance() mPluginExport is not nullptr!");
        mPluginExport = nullptr;
    }
}

bool PluginInstance::reload() {
    auto str = mPluginPath.toStdString();
    auto path = str.c_str();
    
    mLib.close();
    if (!mLib.open(path)) {
        Log::exec(QString("PluginInstance::loadPlugin() Open %1 failed!").arg(path));
        return false;
    }
    if (!mLib.symbol("exports", (void**)(&mPluginExport))) {
        Log::exec(QString("Library::symbol() Symbol %1 failed!").arg(path));
        return false;
    }
    
    mPluginName = mPluginExport->mPluginName;
    Log::exec(QString("PluginInstance::loadPlugin() Plugin Name: %1.").arg(mPluginExport->mPluginName));
    
    SAFE_DELETE(mPlugin);
    mPlugin = mPluginExport->mCreateFunc();
    if (mPlugin == nullptr) {
        Log::exec("PluginInstance::loadPlugin() Plugin Instance is nullptr!");
    } 
    Log::exec("PluginInstance::loadPlugin() Plugin Instancing succeed.");
    return true;
}

bool PluginInstance::join(QString iniPath) {
    if (!runnable()) {
        return false;
    }
    mIniPath = iniPath;
    std::thread(starter, this).join();
    std::thread(progresser, this).join();
    return true;
}

bool PluginInstance::detach(QString iniPath) {
    if (!runnable()) {
        return false;
    }
    
    mIniPath = iniPath;
    std::thread(starter, this).detach();
    std::thread(progresser, this).detach();
    return true;
}

double PluginInstance::progress() const {
    return mProgress.progress();
}

bool PluginInstance::runnable() {
    if (mPlugin == nullptr) {
        Log::exec("PluginInstance::runnable() failed! mpAlgorithm is nullptr.");
        return false;
    } else if (mIsRunning) {
        Log::exec("PluginInstance::runnable() failed! Algorithm is still running.");
        return false;
    }
    return true;
}

QString PluginInstance::pluginName() const {
    return mPluginName;
}

void PluginInstance::starter(PluginInstance *self) {
    Log::exec("PluginInstance::starter() starting starter thread...");
    self->mIsRunning = true;
    self->mPlugin->start(self->mIniPath.toStdString().c_str());
}


void PluginInstance::progresser(PluginInstance *self) {
    Log::exec("PluginInstance::progresser() starting progress thread...");
    
    while (self->mPlugin != nullptr && self->mPlugin->progress() <= 1.0) {
        if (self->mProgress.setProgress(self->mPlugin->progress())) {
            emit self->sigProgress(self->mProgress.progress());
        }
    }
    
    self->mProgress.finish();
    self->mIsRunning = false;
    self->reload();
    
    emit self->sigProgress(self->mProgress.progress());
    emit self->sigFinished();
}

插件管理者

主要负责初始化的时候加载所有插件实例,提供对外的接口,让外部可以得到想要执行的插件。

#include "PluginManager.h"

#include <QDir>
#include <QStringList>

#include "metainfo/SystemMetaInfo.h"

#include "tool/macroTools.h"
#include "tool/Log.h"

PluginManager *PluginManager::instance() {
    static PluginManager pm;
    return &pm;
}

PluginInstance *PluginManager::getPluginIns(QString pluginName) {
    if (mPluginList.end() == mPluginList.find(pluginName)) {
        Log::exec(QString("PluginManager::getPluginIns() Plugin name %1 not found!").arg(pluginName));
        return nullptr;
    }
    return mPluginList[pluginName];
}

bool PluginManager::isNameDuplicated(QString name) {
    if (mPluginList.end() != mPluginList.find(name)) {
        Log::exec(QString("PluginManager::isNameDuplicated() Plugin name %1 already exist!").arg(name));
        return true;
    }
    return false;
}

PluginManager::PluginManager() {
    QString pluginPath{QString("%1/").arg(SYSTEM_META_CONFIG->getQStringValue("Plugin", "path"))};
    QDir dir(pluginPath);
    if (dir.isEmpty()) {
        Log::exec(QString("PluginManager::PluginManager() No plugin found in %1!").arg(pluginPath));
    }
    QStringList list{dir.entryList(QDir::Files)};
    for (QFileInfo item : list) {
        QStringList nameSplit{item.fileName().split(".")};
        if (nameSplit.back() == "so" || nameSplit.back() == "dll") {
            QString pluginFilePath{pluginPath + nameSplit.first()};
            if (!isNameDuplicated(nameSplit.first())) {
                mPluginList[nameSplit.first()] = new PluginInstance(pluginFilePath);
            }
        }
    }
}

PluginManager::~PluginManager() {
    for (auto& item : mPluginList) {
        SAFE_DELETE(item);
    }
}

算法管理

算法管理与插件管理十分类似,只不过算法管理直接内嵌在平台中,而插件算法是独立于平台之外,加载到平台中。
在这里插入图片描述

抽象算法基类

#ifndef ABSTRACTALGORITHM_H
#define ABSTRACTALGORITHM_H

class AbstractAlgorithm {
public:
    AbstractAlgorithm() = default;
    virtual ~AbstractAlgorithm() = default;
    virtual bool start(const char*) = 0;    // .ini path
    virtual bool stop() = 0;
    virtual double progress() = 0;
};

#endif // ABSTRACTALGORITHM_H

算法Map与具体算法注册规范

#define BASE_CLASS AbstractAlgorithm

#define ALGORITHM_MAP AlgorithmMap<BASE_CLASS>::instance()

#define DEFINE_CLASS(className, funcName) \
    className(QString) {\
        ALGORITHM_MAP->regist(#funcName, className::funcName);\
    }\
    className(){}\
    static className className##_;\
    static BASE_CLASS* funcName() {\
        return new className;\
    }

#define REGIST_CLASS(className) \
    className className::className##_(#className);
    
    template<class T>
class AlgorithmMap {
public:
    typedef T*(*FUNCTION)(void);
    void regist(QString funcName, FUNCTION func) {
        mFunctionMap[funcName] = func;
    }
    T* get(const QString funcName) {
        if (mFunctionMap.end() != mFunctionMap.find(funcName)) {
            return mFunctionMap[funcName]();
        } else {
            return nullptr;
        }
    }
    static AlgorithmMap<T>* instance() {
        static AlgorithmMap<T> algoMap;
        return &algoMap;
    }
    QMap<QString, FUNCTION>& funcMap() const {
        return mFunctionMap;
    }
private:
    QMap<QString, FUNCTION> mFunctionMap;
};

#endif // ALGORITHMMAPPER_H

先定义,后注册,注册时候会加载到具体算法Map中

PetCoin

头文件

#ifndef ALGORITHMPETCOIN_H
#define ALGORITHMPETCOIN_H

#include <fstream>

#include "../AlgorithmMap.h"

#include "AlgoPetCoinPara.h"
#include "CoinStruct.h"
#include "CoinTimeRecorder.h"

#include "../PetScan/DataFrameV2.h"

#include "../Calibration/position/PositionMap.h"
#include "../Calibration/energy/EnergyMap.h"

class AlgorithmPetCoin : public AbstractAlgorithm {
public:
    DEFINE_CLASS(AlgorithmPetCoin, PetCoin);
    virtual ~AlgorithmPetCoin();
    bool start(const char *path) override;
    bool stop() override;
    double progress() override;
    double coinRate();
    
private:
    bool convertDataFrameToSingles(DataFrameV2& src, SinglesStruct& dst);
    bool coinEnergy(double energy) const;   // 能量符合,只有在能量窗内的singles才能被选择出来 TODO: 前置能量符合
    void coinTime(SinglesStruct& single);   // 时间符合,只有在时间窗内的singles才能被选择出来 
    int  coinTimeDelayWindow(SinglesStruct& single1, SinglesStruct& single2); //0: in the DW; 1: before the DW; -1: after the DW.
    bool coinPosition(SinglesStruct& single1, SinglesStruct& single2);
    
    AlgoPetCoinPara mPetCoinPara{};
    
    QVector<QVector<int>> mGroupCsv{};
    
    QVector<int> mSinglesNumList{};
    QVector<int> mBdmFileSizeList{};
    
    std::vector<std::ifstream> mBdmFileList{};
    
    SinglesStruct** mSingles;
    SinglesStruct* mSortedSingles{nullptr};  // 合并后1路有序singles数组
    int mSortedIndex{0};   // mSortedSingles的指针
    
    QVector<int> mCurSingleIndexList;
    
    unsigned long long mTotalSinglesNum{0};
    
    QVector<CoinStruct> mCoinList;

    CoinTimeRecorder mCoinTimeRecorder;    // 一个用于时间符合的singles记录器

    int mTotalCoinNum{0};
    
    PositionMap* mPositionMap{nullptr};
    EnergyMap* mEnergyMap{nullptr};
    
    double mProgress{0.0};
    double mCoinRate{0.0};
    
    int mMinSectorDiff{0};
    int mDelayedWindow{0};

};

#endif // ALGORITHMPETCOIN_H

源文件

#include "AlgorithmPetCoin.h"

#include <cmath>
#include <cfloat>

#include <thread>
#include <vector>

#include "PetCoinToMich.h"

#include "tool/IniConfig.h"
#include "tool/Log.h"
#include "tool/TimerClock.h"
#include "tool/CsvTool.h"
#include "tool/macroTools.h"

#include "setting/Setting.h"
#include "metainfo/SystemMetaInfo.h"
#include "metainfo/CaliMetaInfo.h"

REGIST_CLASS(AlgorithmPetCoin);

AlgorithmPetCoin::~AlgorithmPetCoin() {
    SAFE_DELETE(mPositionMap);
    SAFE_DELETE(mEnergyMap);
}

bool AlgorithmPetCoin::start(const char *path) {
    // 1. init para
    IniConfig coinIni(path);
    coinIni.setSegmentName("CoincidenceInfo");
    mPetCoinPara.petPath = coinIni.getQStringValue("petPath");
    mPetCoinPara.coinPath = coinIni.getQStringValue("coinPath");
    //    mPetCoinPara.positionPath = coinIni.getQStringValue("positionPath");
    //    mPetCoinPara.energyPath = coinIni.getQStringValue("energyPath");
    mPetCoinPara.positionSize = SETTING->mPetSetting.petScannerSetting.positionSize;
//    mPetCoinPara.crystalSize = SETTING->mPetSetting.petScannerSetting.crystalNumY;
    mPetCoinPara.crystalNumX = SETTING->mPetSetting.petScannerSetting.crystalNumX;
    mPetCoinPara.crystalNumY = SETTING->mPetSetting.petScannerSetting.crystalNumY;
    mPetCoinPara.crystalNumZ = SETTING->mPetSetting.petScannerSetting.crystalNumZ;
    mPetCoinPara.blockNumX = SETTING->mPetSetting.petScannerSetting.blockNumX;
    mPetCoinPara.blockNumY = SETTING->mPetSetting.petScannerSetting.blockNumY;
    mPetCoinPara.blockNumZ = SETTING->mPetSetting.petScannerSetting.blockNumZ;
    mPetCoinPara.moduleNumX = SETTING->mPetSetting.petScannerSetting.moduleNumX;
    mPetCoinPara.moduleNumY = SETTING->mPetSetting.petScannerSetting.moduleNumY;
    mPetCoinPara.moduleNumZ = SETTING->mPetSetting.petScannerSetting.moduleNumZ;
    mPetCoinPara.bdmNum = SETTING->mPetSetting.petScannerSetting.bdmNum;
    mPetCoinPara.duNum = SETTING->mPetSetting.petScannerSetting.duNum;

    mPetCoinPara.timingWindow = coinIni.getIntValue("timingWindow");
    mPetCoinPara.energyWindowStart = coinIni.getIntValue("energyWindowStart");
    mPetCoinPara.energyWindowEnd = coinIni.getIntValue("energyWindowEnd");
    mPetCoinPara.coinType = coinIni.getQStringValue("coinType");
    
    
    mPetCoinPara.bedIndex = coinIni.getIntValue("bedIndex");
    
    mPetCoinPara.isFastCoin = false;
    
    CALI_META_CONFIG->setSegmentName(SETTING->mPetSetting.curPetDevice);
    SYSTEM_META_CONFIG->setSegmentName("NamePreset");
    QString posTablePath = QString("%1/%2").arg(CALI_META_CONFIG->getQStringValue("positionPath"))
            .arg(SYSTEM_META_CONFIG->getQStringValue("positionTable"));
    QString energyCorrFactorPath = QString("%1/%2").arg(CALI_META_CONFIG->getQStringValue("energyPath"))
            .arg(SYSTEM_META_CONFIG->getQStringValue("energyCorrFactor"));
    mPositionMap = new PositionMap;
    mEnergyMap = new EnergyMap;
    mPositionMap->ReadPositionTable(posTablePath);
    mEnergyMap->readEnergyCorrFactor(energyCorrFactorPath);
    
    int lBdmNum{mPetCoinPara.bdmNum};
    
    mBdmFileSizeList.resize(lBdmNum);
    mSinglesNumList.resize(lBdmNum);
    
    mBdmFileList.resize(lBdmNum);
    
    for (int bdmIndex = 0;bdmIndex < lBdmNum;++bdmIndex) {
        QString lBdmFilePath{QString("%1/%2").arg(mPetCoinPara.petPath)
                    .arg(SYSTEM_META_CONFIG->getQStringValue("Data", "petScanFile").arg(bdmIndex))};
        mBdmFileList[bdmIndex].open(lBdmFilePath.toStdString());
        if (!mBdmFileList[bdmIndex].is_open()) {
            Log::exec(QString("AlgorithmPetCoin::start() Open file %1 failed!").arg(lBdmFilePath));
            return false;
        }
        mBdmFileList[bdmIndex].seekg(0, std::ios_base::end);
        mBdmFileSizeList[bdmIndex] = mBdmFileList[bdmIndex].tellg();
        mBdmFileList[bdmIndex].seekg(0, std::ios_base::beg);
        mSinglesNumList[bdmIndex] = mBdmFileSizeList[bdmIndex] / sizeof(DataFrameV2);
        mTotalSinglesNum += mSinglesNumList[bdmIndex]; 
    }
    
    Log::exec(QString("AlgorithmPetCoin::start() Total singles num = %1").arg(mTotalSinglesNum));
    Log::exec(QString("AlgorithmPetCoin::start() %1 MB memory needed.").arg(double(mTotalSinglesNum) * sizeof(DataFrameV2) / 1024 / 1024));
    
    QString lGroupCsvPath{QString("%1/%2").arg(mPetCoinPara.petPath).arg(SYSTEM_META_CONFIG->getQStringValue("NamePreset", "petGroupFile"))};
    mGroupCsv = CsvTool::readCsvInt(lGroupCsvPath);
    
    if (mGroupCsv.size() != lBdmNum) {
        Log::exec("AlgorithmPetCoin::start() The Group CSV file is illegal!");
        return false;
    }
    
    mSingles = new SinglesStruct*[lBdmNum];
    mSinglesNumList.resize(lBdmNum);
    
    int groupSize{mGroupCsv[0].size()};
    double progressFactor{1.0 / groupSize * 1.0};
    
    QString lCoinFilePath{QString("%1/%2").arg(mPetCoinPara.coinPath)
                .arg(SYSTEM_META_CONFIG->getQStringValue("Data", "petCoinFile").arg(mPetCoinPara.bedIndex))};
    QString lSinglesFilePath{QString("%1/%2").arg(mPetCoinPara.coinPath)
                .arg(QString("Bed%1-singles.dat").arg(mPetCoinPara.bedIndex))};

    for (int groupIndex = 0;groupIndex < groupSize; ++groupIndex) {
        // 2. Data Frame to Singles
        mTotalSinglesNum = 0;
        mSortedIndex = 0;
        mTotalCoinNum = 0;
        std::vector<std::thread> lConvertTasks;

        for (int bdmIndex = 0;bdmIndex < lBdmNum;++bdmIndex) {
//            mTotalSinglesNum += mGroupCsv[bdmIndex][groupIndex];
            lConvertTasks.emplace_back([&, bdmIndex] {
                mSinglesNumList[bdmIndex] = mGroupCsv[bdmIndex][groupIndex];
                auto* lDataFrameArray = new DataFrameV2[mSinglesNumList[bdmIndex]]; // input
                mSingles[bdmIndex] = new SinglesStruct[mSinglesNumList[bdmIndex]]; // output
                mBdmFileList[bdmIndex].read((char*)lDataFrameArray, mSinglesNumList[bdmIndex] * sizeof(DataFrameV2));
                
//                Log::exec(QString("[BDM %1] mBdmFileList[bdmIndex].tellg() = %2").arg(bdmIndex).arg(mBdmFileList[bdmIndex].tellg()));
                
                unsigned actualSinglesIndex{0};
                for (int i = 0;i < mSinglesNumList[bdmIndex];++i) {
                    if (convertDataFrameToSingles(lDataFrameArray[i], mSingles[bdmIndex][actualSinglesIndex])) {
                        ++actualSinglesIndex;
                    }
                }
                SAFE_DELETE_ARRAY(lDataFrameArray);

                mSinglesNumList[bdmIndex] = actualSinglesIndex;
                
                // qsort
                if (!mPetCoinPara.isFastCoin) {
                    qsort(mSingles[bdmIndex], mSinglesNumList[bdmIndex], sizeof(SinglesStruct), [](const void *a, const void *b) {
                        auto *aa = (SinglesStruct *) a;
                        auto *bb = (SinglesStruct *) b;
                        
                        if (aa->timevalue > bb->timevalue) return 1;
                        else if (aa->timevalue < bb->timevalue) return -1;
                        else return 0;
                    });
                }
                
                // check errors
                int error{0};
                for (int i = 0;i < mSinglesNumList[bdmIndex] - 1;++i) {
                    if (mSingles[bdmIndex][i].timevalue > mSingles[bdmIndex][i+1].timevalue) {
                        ++error;
                    }
                }
                if (error) {
                    Log::exec(QString("[BDM %1] Coin unordered count = %2").arg(bdmIndex).arg(error));
                }
                
//                // * save Nsingles files
//                QString lNSinglesFilePath{QString("%1/%2").arg(mPetCoinPara.coinPath)
//                            .arg(QString("Bed%1-singles%2.dat").arg(mPetCoinPara.bedIndex).arg(bdmIndex))};
//                std::ofstream lNSinglesFile(lNSinglesFilePath.toStdString(), std::ios::binary | std::ios::app);
//                if (!lNSinglesFile.is_open()) {
//                    return false;
//                }
//                lNSinglesFile.write((char*)mSingles[bdmIndex], mSinglesNumList[bdmIndex] * sizeof(SinglesStruct));
                
            });

        }
        for (auto& item : lConvertTasks) {
            item.join();
        }

        for (int bdmIndex = 0;bdmIndex < lBdmNum;++bdmIndex) {
            mTotalSinglesNum += mSinglesNumList[bdmIndex];
        }

        mProgress += 0.3 * progressFactor;
        
        // 3. Singles merging.
        mSortedSingles = new SinglesStruct[mTotalSinglesNum];
        
        unsigned* lLoserTree{new unsigned[lBdmNum + 1]};
        SinglesStruct* lLoserTreeNodes{new SinglesStruct[lBdmNum + 1]};
        
        mCurSingleIndexList.clear();
        mCurSingleIndexList.resize(lBdmNum);
        
        for (int i = 0; i < lBdmNum; ++i) {
            mCurSingleIndexList[i] = 0;
            if (mSinglesNumList[i] == 0) {
                lLoserTreeNodes[i].timevalue = DBL_MAX; // Default maximum
            } else {
                lLoserTreeNodes[i] = mSingles[i][0];
            }
            ++mCurSingleIndexList[i];
        }
        auto funcAdjust = [&](int n, int s) {
            int t, temp;
            for (t = (s + n) / 2; t > 0; t = t / 2) {
                if (lLoserTreeNodes[s].timevalue > lLoserTreeNodes[lLoserTree[t]].timevalue) {
                    temp = s;
                    s = lLoserTree[t];
                    lLoserTree[t] = temp;
                }
            }
            lLoserTree[0] = s;
        };
        lLoserTreeNodes[lBdmNum].timevalue = -1.0;
        for (int i = 0; i < lBdmNum; ++i) {
            lLoserTree[i] = lBdmNum;
        }
        for (int i = lBdmNum - 1; i >= 0; --i) {
            funcAdjust(lBdmNum, i);
        }
        int winner;
        while (lLoserTreeNodes[lLoserTree[0]].timevalue != DBL_MAX) {
            winner = lLoserTree[0];
            mSortedSingles[mSortedIndex] = lLoserTreeNodes[winner];
            ++mSortedIndex;
            if (mCurSingleIndexList[winner] >= mSinglesNumList[winner]) {
                lLoserTreeNodes[winner].timevalue = DBL_MAX;
            } else {
                lLoserTreeNodes[winner] = mSingles[winner][mCurSingleIndexList[winner]];
                ++mCurSingleIndexList[winner];
            }
            funcAdjust(lBdmNum, winner);
        }
        SAFE_DELETE_ARRAY(lLoserTree);
        SAFE_DELETE_ARRAY(lLoserTreeNodes);
        
        for (int i = 0;i < lBdmNum;++i) {
            SAFE_DELETE_ARRAY(mSingles[i]);
        }
        
        mProgress += 0.3 * progressFactor;
        
//        // 3.5* Save sorted singles to file
//        std::ofstream lSortedSinglesFile(lSinglesFilePath.toStdString(), std::ios::binary | std::ios::app);
//        if (!lSortedSinglesFile.is_open()) {
//            return false;
//        }
//        lSortedSinglesFile.write((char*)mSortedSingles, mTotalSinglesNum * sizeof(SinglesStruct));
        
        // 4. Sorted Singles to coins
        
        if(mPetCoinPara.coinType == "Delayed Window"){
            mMinSectorDiff = coinIni.getIntValue("minSectorDifference");
            mDelayedWindow = coinIni.getIntValue("delayedTime");
             
            for(mSortedIndex = 0; mSortedIndex < mTotalSinglesNum - 1; ++mSortedIndex){
                for(int nextIndex = mSortedIndex + 1; nextIndex < mTotalSinglesNum; ++nextIndex){
                    int coinTimeStatus = coinTimeDelayWindow(mSortedSingles[mSortedIndex], mSortedSingles[nextIndex]);
                    if(coinTimeStatus == 0){ //in the delayed window
                        if(coinPosition(mSortedSingles[mSortedIndex], mSortedSingles[nextIndex])){
                            mCoinTimeRecorder.first() = mSortedSingles[mSortedIndex];
                            mCoinTimeRecorder.second() = mSortedSingles[nextIndex];
                            mCoinList.append(mCoinTimeRecorder.data);
                            ++mTotalCoinNum;
                            mCoinRate = 2.0 * mTotalCoinNum / (mSortedIndex+1);
                        }
                    } else if(coinTimeStatus == -1){// after delayed window
                        break;
                    } // befor delayed window -> j++.
                }// end for time window
            }           
        }else{
            for (mSortedIndex = 0; mSortedIndex < mTotalSinglesNum; ++mSortedIndex) {
                coinTime(mSortedSingles[mSortedIndex]);
            }
        }
        
        SAFE_DELETE_ARRAY(mSortedSingles);
        
        mProgress += 0.3 * progressFactor;
        
        // 5. Save coin list
        std::ofstream lCoinFile(lCoinFilePath.toStdString(), std::ios::binary | std::ios::app);
        if (!lCoinFile.is_open()) {
            Log::exec(QString("AlgorithmPetCoin::start() Open %1 failed!").arg(lCoinFilePath));
            return false;
        }
        
        lCoinFile.write((char*)mCoinList.data(), mTotalCoinNum * sizeof(CoinStruct));
        mCoinList.clear();
        lCoinFile.close();
        
        
        mProgress += 0.1 * progressFactor;
    }
    
    SAFE_DELETE_ARRAY(mSingles);
    
    // 6. Coin To Mich
    QString lMichFilePath{QString("%1/%2").arg(mPetCoinPara.coinPath)
                         .arg(SYSTEM_META_CONFIG->getQStringValue("Data", "petMichFile").arg(mPetCoinPara.bedIndex))};
    PetCoinToMich::coin2mich(lCoinFilePath, lMichFilePath);
    
    mProgress = 2.0;
    mCoinRate = 0.0;
    return true;
}

bool AlgorithmPetCoin::convertDataFrameToSingles(DataFrameV2 &src, SinglesStruct &dst) {
    /* Position, Energy, Time corrections included */
    unsigned m_nChannelNum = mPetCoinPara.bdmNum;
    //    unsigned moduleNumX = mCoinPetPara.m_nModuleNumX;
    unsigned moduleNumY = mPetCoinPara.moduleNumY;
    //    unsigned moduleNumZ = mCoinPetPara.m_nModuleNumZ;
    //    unsigned blockNumX = mCoinPetPara.m_nBlockNumX;
    unsigned blockNumY = mPetCoinPara.blockNumY;
    unsigned blockNumZ = mPetCoinPara.blockNumZ;
    //    unsigned crystalNumX = mCoinPetPara.m_nCrystalNumX;
    unsigned crystalNumY = mPetCoinPara.crystalNumY;
    unsigned crystalNumZ = mPetCoinPara.crystalNumZ;
    unsigned positionSize = mPetCoinPara.positionSize;
    
    /* Temporary structure to provide BDM and DU info */
    TempSinglesStruct temp;
    temp.globalBDMIndex = src.nBDM;
    temp.localDUIndex = src.nHeadAndDU & (0x0F);
    
    /* Time convertion, from unsigned char[8] to double */
    unsigned long long nTimeTemp;
    nTimeTemp = src.nTime[0];
    for (int i = 1;i <= 7;++i) {
        nTimeTemp <<= 8;
        nTimeTemp |= src.nTime[i];
    }
    temp.timevalue = (double)nTimeTemp;
    
    /* Position correction */
    unsigned originCrystalIndex = mPositionMap->GetPositionTable(temp.globalBDMIndex, temp.localDUIndex)[src.X + src.Y * positionSize];
    unsigned localX = originCrystalIndex % crystalNumZ;
    unsigned localY = originCrystalIndex / crystalNumY;
    temp.localCrystalIndex = localX + (crystalNumY - 1 - localY) * crystalNumZ;
    
    /* Time correction */
    
    /* Energy convertion, from unsigned char[2] to float */
    unsigned nEnergyTemp;
    nEnergyTemp = (src.Energy[0] << 8 | src.Energy[1]);
    temp.energy = (float)nEnergyTemp;
    
    unsigned nCrystalIdInRing = temp.globalBDMIndex % (m_nChannelNum * moduleNumY) * blockNumY * crystalNumY + temp.localDUIndex / blockNumZ * crystalNumY + temp.localCrystalIndex / crystalNumZ;
    unsigned nRingId = temp.globalBDMIndex / (m_nChannelNum * moduleNumY) * blockNumZ * crystalNumZ + temp.localDUIndex % blockNumZ * crystalNumZ + temp.localCrystalIndex % crystalNumZ;
    unsigned nCrystalNumOneRing = crystalNumY * blockNumY * m_nChannelNum;
    
    dst.globalCrystalIndex = nCrystalIdInRing + nRingId * nCrystalNumOneRing;
    /* Energy correction */
    dst.energy = temp.energy * mEnergyMap->getEnergyCorrFactor(temp.globalBDMIndex, temp.localDUIndex, temp.localCrystalIndex)[int(floor(temp.energy / 10))];
    dst.timevalue = temp.timevalue;
    
    return coinEnergy(dst.energy);
}

bool AlgorithmPetCoin::coinEnergy(double energy) const {
    bool isValid = energy >= mPetCoinPara.energyWindowStart && energy <= mPetCoinPara.energyWindowEnd;
    return isValid;
}

void AlgorithmPetCoin::coinTime(SinglesStruct &single) {
    // Kill All 符合方式: 当且仅当时间窗内有两个单事件时记录一组符合事件对
    if (single.timevalue - mCoinTimeRecorder.first().timevalue > mPetCoinPara.timingWindow) {
        if (2 == mCoinTimeRecorder.index) {
            // 如果全局晶体编号不一致,就保存
            if (mCoinTimeRecorder.first().globalCrystalIndex != mCoinTimeRecorder.second().globalCrystalIndex) {
                mCoinList.append(mCoinTimeRecorder.data);
                ++mTotalCoinNum;
                mCoinRate = 2.0 * mTotalCoinNum / (mSortedIndex+1);
            }
        }
        mCoinTimeRecorder.first() = single;
        mCoinTimeRecorder.index = 1;
    } else {
        mCoinTimeRecorder.second() = single;
        ++mCoinTimeRecorder.index;
    }
}

int AlgorithmPetCoin::coinTimeDelayWindow(SinglesStruct &single1, SinglesStruct &single2)
{
    double timeDiff = single2.timevalue - (single1.timevalue + mDelayedWindow);
    if( timeDiff < 0 )
        return 1; // before the DW
    else if( timeDiff <  mPetCoinPara.timingWindow)
        return 0; // in the DW
    else
        return -1; // after the DW
}

bool AlgorithmPetCoin::coinPosition(SinglesStruct &single1, SinglesStruct &single2)
{
    unsigned panelNum = SETTING->mPetSetting.petScannerSetting.panelNum;
    unsigned nCrystalNumOneRing = SETTING->mPetSetting.petScannerSetting.getCrystalNumOneRing();
    unsigned nCrystalNumYInModule = SETTING->mPetSetting.petScannerSetting.getCrystalNumYInModule();
    
    int sector1 = single1.globalCrystalIndex % nCrystalNumOneRing / (nCrystalNumYInModule);
    int sector2 = single2.globalCrystalIndex % nCrystalNumOneRing / (nCrystalNumYInModule);

    if ((sector1 - sector2 + panelNum) % panelNum >= mMinSectorDiff)
        return true;
    else
        return false;
}




bool AlgorithmPetCoin::stop() {
    return false;
}

double AlgorithmPetCoin::progress() {
    return mProgress;
}

double AlgorithmPetCoin::coinRate() {
    return mCoinRate;
}

算法实例

头文件

#ifndef ALGORITHMINSTANCE_H
#define ALGORITHMINSTANCE_H

#include "AbstractAlgorithm.h"

#include <memory>

#include <QObject>
#include <QString>

class AlgorithmInstance : public QObject {
    Q_OBJECT
public:
    AlgorithmInstance(QString algoName);
    virtual ~AlgorithmInstance();
    
    void reload();
    virtual bool join(QString iniPath) = 0;     // run algorithm in current thread
    virtual bool detach(QString iniPath) = 0;   // run algorithm in detach thread
    
    double progress() const;
    
signals:
    void sigProgress(double);
    void sigFinished();
    
protected:
    bool runnable();
    
    QString mAlgoName;
    QString mIniPath;
    AbstractAlgorithm* mpAlgorithm{nullptr};
    double mProgress{0.0};
    bool mIsRunning{false};
    
//private:
//    static void starter(AlgorithmInstance* self);
//    static void progresser(AlgorithmInstance* self);
};

#endif // ALGORITHMINSTANCE_H

源文件

#include "AlgorithmInstance.h"

#include <thread>

#include "tool/macroTools.h"
#include "tool/Log.h"

#include "AlgorithmMap.h"

AlgorithmInstance::AlgorithmInstance(QString algoName) {
    mAlgoName = algoName;
    reload();
}

AlgorithmInstance::~AlgorithmInstance() {
    SAFE_DELETE(mpAlgorithm);
}

void AlgorithmInstance::reload() {
    SAFE_DELETE(mpAlgorithm);
    mpAlgorithm = ALGORITHM_MAP->get(mAlgoName);
}

//bool AlgorithmInstance::join(QString iniPath) {
//    if (!runnable()) {
//        return false;
//    }
//    mIniPath = iniPath;
//    std::thread(starter, this).join();
//    std::thread(progresser, this).join();
//    return true;
//}

//bool AlgorithmInstance::detach(QString iniPath) {
//    if (!runnable()) {
//        return false;
//    }
//    mIniPath = iniPath;
//    std::thread(starter, this).detach();
//    std::thread(progresser, this).detach();
//    return true;
//}

double AlgorithmInstance::progress() const {
    return mProgress;
}

bool AlgorithmInstance::runnable() {
    if (mpAlgorithm == nullptr) {
        Log::exec("AlgorithmInstance::runnable() failed! mpAlgorithm is nullptr.");
        return false;
    } else if (mIsRunning) {
        Log::exec("AlgorithmInstance::runnable() failed! Algorithm is still running.");
        return false;
    }
    return true;
}

//void AlgorithmInstance::starter(AlgorithmInstance* self) {
//    Log::exec("AlgorithmInstance::starter() starting starter thread...");
//    self->mIsRunning = true;
//    self->mpAlgorithm->start(self->mIniPath.toStdString().c_str());
//}

//void AlgorithmInstance::progresser(AlgorithmInstance* self) {
//    Log::exec("AlgorithmInstance::progresser() starting progress thread...");
//    double preProgress = 0.0;
//    double curProgress = 0.0;
//    while (self->mpAlgorithm != nullptr && self->mpAlgorithm->progress() <= 1.0) {
//        curProgress = self->mpAlgorithm->progress();
//        if (curProgress - preProgress > 0.01 || curProgress - preProgress < -0.01) {
//            preProgress = curProgress;
//            self->mProgress = curProgress;
//            emit self->sigProgress(self->mProgress);
//        }
//    }
    
//    self->mProgress = 2.0;
//    self->mIsRunning = false;
//    self->reload();
    
//    emit self->sigProgress(self->mProgress);
//    emit self->sigFinished();
//}

每一个插件实例中存放了具体需要的算法,获取的算法的时候直接通过算法管理者的Map得到算法实例即可。

算法管理者

#ifndef ALGORITHMMANAGER_H
#define ALGORITHMMANAGER_H

#include <QMap>

#include "AlgorithmInstance.h"

#define ALGORITHM_MANAGER AlgorithmManager::instance()

class AlgorithmManager {
public:
    static AlgorithmManager* instance();
    AlgorithmInstance* getAlgoIns(QString algoName);
    
    template<class T>
    T* getAlgoIns(QString algoName) {
        return (T*)mAlgorithmList[algoName];
    }
    
private:
    AlgorithmManager();
    virtual ~AlgorithmManager();
    
    QMap<QString, AlgorithmInstance*> mAlgorithmList;
};

#endif // ALGORITHMMANAGER_H


//cpp
#include "AlgorithmManager.h"

#include "tool/macroTools.h"

#include "algorithm/PetScan/AlgoInsPetScan.h"
#include "algorithm/PetCoin/AlgoInsPetCoin.h"

AlgorithmManager *AlgorithmManager::instance() {
    static AlgorithmManager am;
    return &am;
}

AlgorithmInstance *AlgorithmManager::getAlgoIns(QString algoName) {
    return mAlgorithmList[algoName];
}

AlgorithmManager::AlgorithmManager() {
    mAlgorithmList["PetScan"] = (AlgorithmInstance*)(new AlgoInsPetScan("PetScan"));
    mAlgorithmList["PetCoin"] = (AlgorithmInstance*)(new AlgoInsPetCoin("PetCoin"));
}

AlgorithmManager::~AlgorithmManager() {
    for (auto& item : mAlgorithmList) {
        SAFE_DELETE(item);
    }
}

管理者构造的时候就把具体实例加载进来。
外部只需要通过Map获得算法实例即可。

任务队列机制

抽象任务

#ifndef ABSTRACTTASK_H
#define ABSTRACTTASK_H

#include <QObject>
#include <QMetaType>

class AbstractTask : public QObject {
    Q_OBJECT
public:
    AbstractTask() {
        qRegisterMetaType<TaskStatus>("TaskStatus");
    }
    virtual ~AbstractTask() = default;
    enum TaskStatus {
        RUNNING = 0,
        PAUSED,
        WAITING,
        STOPPED,
        FINISHED,
        ERRORED,
        STOPPING,
        PAUSING,
        RESUMING,
        STATUS_NUM
    };
    TaskStatus status() const {return mStatus;}
    virtual bool start() = 0;
    
    void setErrored() {mStatus = ERRORED;}
    
signals:
    void sigStarted();
    void sigPaused();
    void sigResumed();
    void sigFinished(TaskStatus nStatus);
    void sigProgress(double fValue);
    void sigTimePassed(unsigned int nTime);
    
protected:
    TaskStatus mStatus;
};

#endif // ABSTRACTTASK_H

qRegisterMetaType的介绍

具体任务

具体的任务会有对应的插件实例或者算法实例。

重建任务:

#ifndef RECONTASKPET_H
#define RECONTASKPET_H

#include "plugin/PluginManager.h"

#include "../AbstractTask.h"

class ReconTaskPet : public AbstractTask {
    Q_OBJECT
public:
    ReconTaskPet(QString strIniPath, int nBedIndex, int nBedNum);
    virtual ~ReconTaskPet() = default;
    
    bool start() override;
    
private slots:
    void onPetReconFinished();
    
private:
    PluginInstance* mpPlugPetRecon;
    QString mIniPath;
    int mBedIndex;
    int mBedNum;
};

#endif // RECONTASKPET_H

//cpp
#include "ReconTaskPet.h"

#include "tool/Log.h"

#include "metainfo/SystemMetaInfo.h"

ReconTaskPet::ReconTaskPet(QString strIniPath, int nBedIndex, int nBedNum) :
    mpPlugPetRecon{PLUGIN_MANAGER->getPluginIns(SYSTEM_META_CONFIG->getQStringValue("Plugin", "osemName"))},
    mIniPath{strIniPath}, mBedIndex{nBedIndex}, mBedNum{nBedNum} {}

bool ReconTaskPet::start() {
    emit sigStarted();
    mStatus = RUNNING;
    connect(mpPlugPetRecon, &PluginInstance::sigProgress, this, &ReconTaskPet::sigProgress);
    connect(mpPlugPetRecon, &PluginInstance::sigFinished, this, &ReconTaskPet::onPetReconFinished);
    return mpPlugPetRecon->detach(mIniPath);
}

void ReconTaskPet::onPetReconFinished() {
    disconnect(mpPlugPetRecon, &PluginInstance::sigProgress, this, &ReconTaskPet::sigProgress);
    disconnect(mpPlugPetRecon, &PluginInstance::sigFinished, this, &ReconTaskPet::onPetReconFinished);
    Log::exec(QString("[%1 / %2] ReconTaskPet::onPetReconFinished() PET reconstruct task finished!").arg(mBedIndex).arg(mBedNum));
    emit sigFinished(FINISHED);
}

符合任务:

#ifndef COINTASK_H
#define COINTASK_H

#include "algorithm/AlgorithmManager.h"
#include "algorithm/PetCoin/AlgoInsPetCoin.h"

#include "../AbstractTask.h"
#include "../TaskType.h"

class CoinTask : public AbstractTask {
    Q_OBJECT
public:
    CoinTask(QString strIniPath, int nBedIndex, int nBedNum);
    virtual ~CoinTask() = default;
    
    bool start() override;
    
private slots:
    void onPetCoinFinished();
    
private:
    AlgoInsPetCoin* mpAlgoPetCoin;
    QString mIniPath;
    int mBedIndex;
    int mBedNum;
    
signals:
    void sigCoinRate(double);
};

#endif // COINTASK_H


//cpp
#include "CoinTask.h"

#include "tool/Log.h"

CoinTask::CoinTask(QString strIniPath, int nBedIndex, int nBedNum) :
    mpAlgoPetCoin{ALGORITHM_MANAGER->getAlgoIns<AlgoInsPetCoin>("PetCoin")},
    mIniPath{strIniPath},
    mBedIndex{nBedIndex},
    mBedNum{nBedNum} {
}

bool CoinTask::start() {
    emit sigStarted();
    mStatus = RUNNING;
    connect(mpAlgoPetCoin, &AlgorithmInstance::sigProgress, this, &CoinTask::sigProgress);
    connect(mpAlgoPetCoin, &AlgorithmInstance::sigFinished, this, &CoinTask::onPetCoinFinished);
    connect(mpAlgoPetCoin, &AlgoInsPetCoin::sigCoinRate, this, &CoinTask::sigCoinRate);
    return mpAlgoPetCoin->detach(mIniPath);
}

void CoinTask::onPetCoinFinished() {
    disconnect(mpAlgoPetCoin, &AlgorithmInstance::sigProgress, this, &CoinTask::sigProgress);
    disconnect(mpAlgoPetCoin, &AlgorithmInstance::sigFinished, this, &CoinTask::onPetCoinFinished);
    disconnect(mpAlgoPetCoin, &AlgoInsPetCoin::sigCoinRate, this, &CoinTask::sigCoinRate);
    QString msg{QString("[%1 / %2] CoinTask::onPetCoinFinished() PET coincidence task finished!").arg(mBedIndex).arg(mBedNum)};
    Log::exec(msg);
    emit sigFinished(FINISHED);
}

任务管理者

#ifndef TASKMANAGER_H
#define TASKMANAGER_H

#include <QObject>

#include "TaskType.h"

#include "TaskQueue.h"

#define TASK_MANAGER TaskManager::instance()

class TaskManager : public QObject {
    Q_OBJECT
public:

    static TaskManager* instance();
    
    void start(TaskType nType);
    bool isRunning(TaskType nType);
    bool isEmpty(TaskType nType);
    AbstractTask* getCurTask(TaskType nType);
    TaskQueue* getQueue(TaskType nType);
    int leftTaskNum(TaskType nType);
    bool appendTask(AbstractTask* pTask, TaskType nType);
    void removeTask(AbstractTask* pTask, TaskType nType);
    
    QVector<AbstractTask*>* getWaitTaskList(TaskType nType);
    QVector<AbstractTask*>* getFinishedTaskList(TaskType nType);
    
private:
    TaskManager();
    virtual ~TaskManager();
    
    TaskQueue* mpQueue[TASK_TYPE_NUM];
};
#endif // TASKMANAGER_H
#include "TaskManager.h"

#include "tool/macroTools.h"

TaskManager* TaskManager::instance() {
    static TaskManager tm;
    return &tm;
}

void TaskManager::start(TaskType nType) {
    mpQueue[nType]->start();
}

bool TaskManager::isRunning(TaskType nType) {
    return mpQueue[nType]->isTaskRunning();
}

bool TaskManager::isEmpty(TaskType nType) {
    return mpQueue[nType]->leftTask() == 0;
}

AbstractTask *TaskManager::getCurTask(TaskType nType) {
    return mpQueue[nType]->getCurTask();
}

TaskQueue *TaskManager::getQueue(TaskType nType) {
    return mpQueue[nType];
}

int TaskManager::leftTaskNum(TaskType nType) {
    return mpQueue[nType]->leftTask();
}

bool TaskManager::appendTask(AbstractTask *pTask, TaskType nType) {
    return mpQueue[nType]->appendTask(pTask);
}

void TaskManager::removeTask(AbstractTask *pTask, TaskType nType) {
    mpQueue[nType]->removeTask(pTask);
}

QVector<AbstractTask*>* TaskManager::getWaitTaskList(TaskType nType) {
    return mpQueue[nType]->getWaitingTaskList();
}

QVector<AbstractTask *> *TaskManager::getFinishedTaskList(TaskType nType) {
    return mpQueue[nType]->getFinishedTaskList();
}

TaskManager::TaskManager() {
    for (int i = 0;i < TASK_TYPE_NUM;++i) {
        mpQueue[i] = new TaskQueue;
        mpQueue[i]->SetAutoRemoveFinished();
    }
}

TaskManager::~TaskManager() {
    for (int i = 0;i < TASK_TYPE_NUM;++i) {
        SAFE_DELETE(mpQueue[i]);
    }
}

//cpp

有多个任务队列,每一种任务都是一个单独的队列,每个队列互相独立运行。
主要负责添加、移除、运行任务。

任务队列

#ifndef TASKQUEUE_H
#define TASKQUEUE_H

#include <QObject>
#include "AbstractTask.h"

class TaskQueue : public QObject {
    Q_OBJECT
public:
    TaskQueue(bool bIsAuto = false, QObject *parent = nullptr);
    virtual ~TaskQueue() = default;
    void SetAutoStart(bool bIsAuto = true);
    void SetAutoRemoveFinished(bool bIsAuto = true);
    
    bool isTaskRunning() {return mIsTaskRunning;}
    bool isAutoRunning() {return mIsAutoRunning;}
    
    void start();
    bool appendTask(AbstractTask* pTask);
    bool removeTask(AbstractTask* pTask);
    void removeAllFinishedTask();
    void removeAllWaitingTask();
    AbstractTask* getCurTask() {return mpCurTask;}
    QVector<AbstractTask*>* getWaitingTaskList() {return &mTaskQueueReady;}
    QVector<AbstractTask*>* getFinishedTaskList() {return &mTaskQueueFinished;}
    
    int leftTask() {return mTaskQueueReady.size();}
    int finishedTask() {return mTaskQueueFinished.size();}
    
signals:
    void sigReadyTaskCount(int nCount);
    void sigQueueFinished(bool bSuccess = true);
    void sigTaskFinished(AbstractTask::TaskStatus nStatus);
    void sigProgress(double dValue);
    void sigTimePassed(unsigned nTime);
    
private slots:
    void onTaskFinished(AbstractTask::TaskStatus nStatus);
    bool onStartNext();
    
private:
    template <typename ForwardIterator>
    void deleteAllTask(ForwardIterator begin, ForwardIterator end);

    QVector<AbstractTask*> mTaskQueueReady;
    QVector<AbstractTask*> mTaskQueueFinished;

    AbstractTask* mpCurTask;

    bool mIsTaskRunning;
    bool mIsAutoRunning;
    bool mIsAutoRemove;
    bool mIsStopQueue;
    bool mLastSuccess;
};

#endif // TASKQUEUE_H


//cpp
#include "TaskQueue.h"

#include "tool/macroTools.h"
#include "tool/Log.h"

TaskQueue::TaskQueue(bool bIsAuto, QObject *parent) 
    : QObject(parent)
    , mpCurTask{nullptr}
    , mIsTaskRunning{false}
    , mIsAutoRunning{bIsAuto}
    , mIsAutoRemove{false}
    , mIsStopQueue{false}
    , mLastSuccess{true} {}

void TaskQueue::SetAutoStart(bool bIsAuto) {
    mIsAutoRunning = bIsAuto;
    
    if(!mIsTaskRunning && mIsAutoRunning) {
        onStartNext();
    }
}

void TaskQueue::SetAutoRemoveFinished(bool bIsAuto) {
    mIsAutoRemove = bIsAuto;
}

void TaskQueue::start() {
    if (!mIsTaskRunning) {
        onStartNext();
    }
}

bool TaskQueue::appendTask(AbstractTask *pTask) {
    mTaskQueueReady.append(pTask);  //添加到任务队列
    
    emit sigReadyTaskCount(leftTask());
    
    connect(pTask, &AbstractTask::sigFinished, this, &TaskQueue::onTaskFinished);
    connect(pTask, &AbstractTask::sigProgress, this, &TaskQueue::sigProgress);
    connect(pTask, &AbstractTask::sigTimePassed, this, &TaskQueue::sigTimePassed);
    
    if (!mIsTaskRunning && mIsAutoRunning) {
        return onStartNext();
    }
    return true;
}

bool TaskQueue::removeTask(AbstractTask* pTask) {
    bool result{true};
    
    switch (pTask->status()) {
    case AbstractTask::RUNNING :
    case AbstractTask::STOPPING :
    case AbstractTask::PAUSING :
    case AbstractTask::PAUSED : {
        result = false;
    } break;    
    case AbstractTask::WAITING : {
        mTaskQueueReady.removeAll(pTask);
        emit sigReadyTaskCount(leftTask());
        SAFE_DELETE(pTask);
    } break;
    case AbstractTask::STOPPED :
    case AbstractTask::ERRORED :
    case AbstractTask::FINISHED : {
        mTaskQueueReady.removeAll(pTask);
        SAFE_DELETE(pTask);
    } break;
    default: break;
    }
    
    return result;
}

void TaskQueue::removeAllFinishedTask() {
    deleteAllTask(mTaskQueueFinished.begin(), mTaskQueueFinished.end());
    mTaskQueueFinished.clear();
}

void TaskQueue::removeAllWaitingTask() {
    deleteAllTask(mTaskQueueReady.begin(), mTaskQueueReady.end());
    mTaskQueueReady.clear();
}

void TaskQueue::onTaskFinished(AbstractTask::TaskStatus nStatus) {
    if (mpCurTask) {
        mLastSuccess = (mpCurTask->status() == AbstractTask::FINISHED);
        mTaskQueueFinished.append(mpCurTask);
    }
    
    mIsTaskRunning = false;
    
    emit sigTaskFinished(nStatus);
    
    onStartNext();
}

bool TaskQueue::onStartNext() {
    bool result{true};
    
    if (!mTaskQueueReady.isEmpty()) {
        mpCurTask = mTaskQueueReady.takeFirst();
//        const auto status = mpCurTask->status();
        
        mIsTaskRunning = true;
        emit sigReadyTaskCount(leftTask());
        
        result = mpCurTask->start();
        if (!result) {
            Log::exec("TaskQueue::onStartNext() mpCurTask->start() errored!");
            mpCurTask->setErrored();
        }
    } else {
        if (mIsStopQueue) {
            mIsStopQueue = false;
            removeAllFinishedTask();
        }
        
        if (mIsAutoRemove) {
            removeAllFinishedTask();
        }
        
        mIsTaskRunning = false;
        mpCurTask = nullptr;
        
        emit sigQueueFinished(mLastSuccess);
    }
    
    return result;
}

template<typename ForwardIterator>
void TaskQueue::deleteAllTask(ForwardIterator begin, ForwardIterator end) {
    while (begin != end) {
        SAFE_DELETE(*begin);
        ++begin;
    }
}


版权声明:本文为zzh123353原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>