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

news2024/12/28 5:32:23

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

  • 插件管理
    • 抽象插件基类
    • 插件导入导出规范
      • __attribute__((visibility("default")))
    • 插件实例
    • 插件管理者
  • 算法管理
    • 抽象算法基类
    • 算法Map与具体算法注册规范
      • PetCoin
    • 算法实例
    • 算法管理者
  • 任务队列机制
    • 抽象任务
    • 具体任务
    • 任务管理者
    • 任务队列

插件管理

插件管理者执行构造函数的时候,加载所有插件实例,每一个插件实例在构造的时候加载它的插件,外部使用者通过插件管理者的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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/124089.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“浪潮信息龙蜥联合实验室”正式成立!2万+人在线,带你一文读懂MeetUp精彩瞬间

12 月 24 日&#xff0c;龙蜥社区&#xff08;OpenAnolis&#xff09; “走进系列” 第 4 期——走进浪潮信息 MeetUp 于线上开展并圆满结束。本次走进浪潮信息 MeetUp 线上观看 2 万人次&#xff0c;收回调研问卷近 500 份&#xff0c;直播间万人参与互动。本次 MeetUp 汇集了…

windows 10管理多版本nodejs

在实际的开发中,不同的项目使用的nodejs的版本不一致。又不想升级或者降低项目的版本。这时就需要灵活的切换本地开发环境的nodejs版本。这里推荐使用nvm&#xff08;一个管理nodejs版本的工具&#xff09;&#xff0c;亲测实用。 1、下载地址 https://github.com/coreybutle…

Biniware Run V6.1.0 快速启动工具中文版

前言 Biniware Run是一款便携式Windows桌面工具&#xff0c;可让您从一个地方快速访问自己喜欢的网站地址&#xff0c;文件和文件夹。只需从桌面拖放任何网站地址&#xff0c;文件或文件夹内的彩色圆圈内&#xff0c;您就可以使用这个方便的软件轻松访问您感兴趣的所有内容。 …

SpringCloud之服务治理Eureka

1.服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现&#xff1f; 服务注册和发现的意思是服务进程在注册中心注册自己的位置&#xff0c;客户端应用进程向注册中心发起查询&#xff0c;来获取服务的位置&#xff0c;服务发现的一个重要作用就是提供一个可用的服务列…

【Linux】Linux调试器--gdb的使用

有时候&#xff0c;我们并不需要被教导&#xff0c;而是应该被不断的提醒。 文章目录一、gdb的介绍二、debug和realease版本的区别三、gdb的使用1.显示代码&#xff1a; l行号&#xff08;list&#xff09;指令2.设置断点&#xff1a; b行号&#xff08;breakpoint&#xff09…

HTML5 定位

文章目录HTML5 定位geolocation简介getCurrentPosition()watchPosition() 和 clearWatch()百度地图HTML5 定位 geolocation 简介 在HTML5中&#xff0c;可以使用geolocation对象来获取用户的地理位置信息。 语法 window.navigator.geolocation //简写为 navigator.geoloca…

uni-app HBuilderX项目转为cli项目及踩坑记录

uni-app有两种创建创建项目的方式&#xff0c;通过HBuilderX可视化界面进行创建和通过vue-cli命令行&#xff0c;两者的区别可以参考uni-app官网-可视化方式的区别 其中cli项目是可以直接运行在hx中的&#xff0c;相比hx项目&#xff0c;cli的好处还有可以自定义环境变量和自定…

借助“云上”SPSS降低未来数据分析的不确定性

生活工作中我们常常会遇到这样或那样的困难&#xff0c;比如不得不临时居家办工&#xff0c;却发现家中电脑没有安装工作中的必备软件&#xff0c;比如毕业论文写到一半&#xff0c;同学告诉你&#xff0c;新版的软件升级加强了某个模型&#xff0c;能让你更好的完成论文。软件…

浅析从DWARF到BTF @龙蜥社区eBPF SIG

一、背景 一个程序会经历编码、编译、运行的过程&#xff0c;但所有的开发几乎都不可能是一帆风顺的&#xff0c;总会有些意想不到的错误&#xff0c;这时便需要调试。那么调试器使用的调试信息是从哪里来的呢&#xff1f;答案就是从编译后的文件中来的(依赖编译的时候使用特定…

Kubernetes使用Ingress Nginx流量代理

理论了解 1、ingress简介 kubernetes官方文档 Ingress 是 kubernetes API 中的标准资源类型之一&#xff0c;ingress 实现的功能是在应用层对客户端请求的 host 名称或请求的 URL 路径把请求转发到指定的 service 资源的规则&#xff0c;即用于将 kubernetes 集群外部的请求…

数字孪生水电站:发电流程三维可视化优化

从大禹治水到三峡大坝的建造&#xff0c;人类为控制和调配自然界的地表水和地下水&#xff0c;修建了许多的水利工程。对水资源进行了广泛的开发利用&#xff0c;诸如农业灌溉、工业和生活用水、水力发电、航运、港口运输、淡水养殖、旅游等。 将图扑软件与 GIS、粒子仿真、虚拟…

动作捕捉系统用于微创手术

微创手术是医生通过病人体表的微小切口&#xff0c;将细长的手术工具探入病人体内进行手术操作。与传统的开口手术相比&#xff0c;这种方式可减少手术对病人造成的创伤&#xff0c;缩短恢复时间。但是&#xff0c;微创手术也给医生的操作带来了一系列困难&#xff1a;比如受小…

Autoform R10中文版安装说明教程

1、安装R8的服务RLM_v12.0BL2 2、拷贝文件到相关目录&#xff08;1、许可证&#xff0c;C:\Program Files安装许可的位置。。。直接停止服务后替换R10 BIN文件 然后改环境变量&#xff08;这里可以直接改&#xff0c;也可以删掉然后重新输入&#xff0c;建议删掉后输入&#x…

上海亚商投顾:创业板缩量跌近1% 血氧仪概念逆市大涨

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪沪指早间低开高走&#xff0c;盘中一度拉升翻红&#xff0c;午后又再度下挫&#xff0c;深成指、创业板指均跌近1%。…

5G网络的关键技术及特点,面临的挑战!

01 5G关键技术 超密集组网&#xff1a;5G需要满足热点高容量场景&#xff08;高流量密度、高速率&#xff09; 超密集组网&#xff1a;大量增加小基站&#xff0c;以空间换性能 基站一般包括&#xff1a;宏基站和小基站 宏基站:即“铁塔站”&#xff0c;一般覆盖范围数千米…

Linux课程笔记

Linux基础命令 Linux的目录结构 /&#xff0c;根目录是最顶级的目录了Linux只有一个顶级目录&#xff1a;/路径描述的层次关系同样适用/来表示/home/itheima/a.txt&#xff0c;表示根目录下的home文件夹内有itheima文件夹&#xff0c;内有a.txt ls命令 功能&#xff1a;列出…

【北邮】计算机组成原理实验:实验一 运算器组成实验

实验一 运算器组成实验 实验目的 ⑴熟悉逻辑测试笔的使用方法。 ⑵熟悉 TEC-8 模型计算机的节拍脉冲 T1、T2、T3&#xff1b; ⑶熟悉双端口通用寄存器组的读写操作&#xff1b; ⑷熟悉运算器的数据传送通路&#xff1b; ⑸验证 74LS181 的加、减、与、或功能&#xff1…

Python数据容器(五)

python学习之旅&#xff08;五&#xff09; &#x1f44d;基础语法部分笔记(一) &#x1f44d;条件判断部分笔记(二) &#x1f44d;循环语句部分笔记(三) &#x1f44d;函数使用部分笔记(四) &#x1f44d;数据容器部分笔记(五) 一.数据容器 一种可以容纳多份数据的数据类型&am…

kail - 扫描与爆破

数据来源 扫描技术 背景 在渗透测试过程中&#xff0c;为了节省人力和时间&#xff0c;通常采用手工和工具相结合的方式。使用工具&#xff0c;就是将一些机械性的操作自动化实现&#xff0c;用来提高渗透测试的效率。例如&#xff0c;寻找内网网段[10.10.10,20/24]所有在线主…

MySQL窗口函数 和 阿里云日志15日留存率仪表盘统计脚本实现

窗口函数的官方描述&#xff1a;窗口函数对一组查询行执行类似聚合的操作。但是&#xff0c;虽然聚合操作将查询行分组为单个结果行&#xff0c;但窗口函数会为每个查询行生成一个结果&#xff0c;发生函数评估的行称为当前行&#xff0c;与发生函数评估的当前行相关的查询行构…