diff --git a/src/applications/mne_scan/libs/scShared/Plugins/abstractplugin.h b/src/applications/mne_scan/libs/scShared/Plugins/abstractplugin.h index 03d4f387d88..9e4a8ea14a4 100644 --- a/src/applications/mne_scan/libs/scShared/Plugins/abstractplugin.h +++ b/src/applications/mne_scan/libs/scShared/Plugins/abstractplugin.h @@ -50,7 +50,7 @@ // QT INCLUDES //============================================================================================================= -#include +#include #include #include #include @@ -76,7 +76,7 @@ namespace SCSHAREDLIB * * @brief The AbstractPlugin class is the base interface class of all plugins. */ -class SCSHAREDSHARED_EXPORT AbstractPlugin : public QThread +class SCSHAREDSHARED_EXPORT AbstractPlugin : public QObject { Q_OBJECT diff --git a/src/applications/mne_scan/libs/scShared/Plugins/threads.h b/src/applications/mne_scan/libs/scShared/Plugins/threads.h new file mode 100644 index 00000000000..b153f013830 --- /dev/null +++ b/src/applications/mne_scan/libs/scShared/Plugins/threads.h @@ -0,0 +1,94 @@ +//============================================================================================================= +/** + * @file threads.h + * @author Gabriel Motta + * @since 0.1.9 + * @date January, 2022 + * + * @section LICENSE + * + * Copyright (C) 2022, Gabriel Motta. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * * Neither the name of MNE-CPP authors nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + * @brief Contains threading classes. + * + */ + +#ifndef MNESCAN_THREADS_H +#define MNESCAN_THREADS_H + +//============================================================================================================= +// INCLUDES +//============================================================================================================= + +#include +#include +#include + +//============================================================================================================= +// DEFINE NAMESPACE SCSHAREDLIB +//============================================================================================================= + +namespace SCSHAREDLIB +{ + +class Thread +{ +public: + //========================================================================================================= + /** + * Constructs an "empty" object. + */ + Thread(): m_bIsRunning(false) {} + + + template + //========================================================================================================= + /** + * Constructs a thread object to run a function in a separate thread. + * + * @param[in] func function to be run in separate thread + * @param[in] args function arguments. + * (Note - member functions need to be passed usually-implicit 'this' pointer) + */ + Thread(Function&& func, Args&&... args): m_thread(func, args...), m_bIsRunning(true) {} + + //========================================================================================================= + /** + * Returns whether the thread is running. + */ + bool isRunning() const {return m_bIsRunning;} + + //========================================================================================================= + /** + * Runs a function as a thread. Thread is deleted once function is finished. Not bound by caller's scope. + */ + template + static void run(Function&& func, Args&&... args){Thread(func, args...).m_thread.detach();} + +private: + std::thread m_thread; /**< The actual thread. */ + std::atomic_bool m_bIsRunning; /**< Whether the thred is runing. */ +}; + +}//namespace + +#endif // MNESCAN_THREADS_H diff --git a/src/applications/mne_scan/plugins/averaging/averaging.cpp b/src/applications/mne_scan/plugins/averaging/averaging.cpp index 7aae3b63df6..0861c24b41d 100644 --- a/src/applications/mne_scan/plugins/averaging/averaging.cpp +++ b/src/applications/mne_scan/plugins/averaging/averaging.cpp @@ -77,6 +77,7 @@ using namespace Eigen; Averaging::Averaging() : m_pCircularBuffer(CircularBuffer::SPtr::create(40)) +, m_bProcessOutput(false) { } @@ -84,7 +85,7 @@ Averaging::Averaging() Averaging::~Averaging() { - if(this->isRunning()) + if(m_bProcessOutput) stop(); } @@ -106,7 +107,8 @@ void Averaging::unload() bool Averaging::start() { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&Averaging::run, this); return true; } @@ -115,8 +117,11 @@ bool Averaging::start() bool Averaging::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_bPluginControlWidgetsInit = false; @@ -406,7 +411,7 @@ void Averaging::onChangeBaselineActive(bool state) void Averaging::onNewEvokedSet(const FIFFLIB::FiffEvokedSet& evokedSet, const QStringList& lResponsibleTriggerTypes) { - if(!this->isRunning()) { + if(!m_bProcessOutput) { return; } @@ -439,7 +444,7 @@ void Averaging::run() FIFFLIB::FiffEvokedSet evokedSet; QStringList lResponsibleTriggerTypes; - while(!isInterruptionRequested()){ + while(m_bProcessOutput){ if(m_pCircularBuffer->pop(evokedSet)) { m_qMutex.lock(); lResponsibleTriggerTypes = m_lResponsibleTriggerTypes; diff --git a/src/applications/mne_scan/plugins/averaging/averaging.h b/src/applications/mne_scan/plugins/averaging/averaging.h index 5b89f78a7ad..7f404c98da6 100644 --- a/src/applications/mne_scan/plugins/averaging/averaging.h +++ b/src/applications/mne_scan/plugins/averaging/averaging.h @@ -47,6 +47,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -237,6 +240,9 @@ class AVERAGINGSHARED_EXPORT Averaging : public SCSHAREDLIB::AbstractAlgorithm QMap m_mapStimChsIndexNames; /**< The currently available stim channels and their corresponding index in the data. */ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; + signals: void stimChannelsChanged(const QMap& mapStimChsIndexNames); void fiffChInfoChanged(const QList& fiffChInfoList); diff --git a/src/applications/mne_scan/plugins/babymeg/babymeg.cpp b/src/applications/mne_scan/plugins/babymeg/babymeg.cpp index 533152be07b..4be61037d08 100644 --- a/src/applications/mne_scan/plugins/babymeg/babymeg.cpp +++ b/src/applications/mne_scan/plugins/babymeg/babymeg.cpp @@ -88,6 +88,7 @@ BabyMEG::BabyMEG() , m_sFiffProjections(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/babymeg/header.fif") , m_sFiffCompensators(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/babymeg/compensator.fif") , m_sBadChannels(QCoreApplication::applicationDirPath() + "/../resources/mne_scan/plugins/babymeg/both.bad") +, m_bProcessOutput(false) { m_pActionSqdCtrl = new QAction(QIcon(":/images/sqdctrl.png"), tr("Squid Control"),this); // m_pActionSetupProject->setShortcut(tr("F12")); @@ -107,7 +108,7 @@ BabyMEG::BabyMEG() BabyMEG::~BabyMEG() { - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } @@ -208,7 +209,8 @@ bool BabyMEG::start() initConnector(); // Start thread - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&BabyMEG::run, this); return true; } @@ -217,8 +219,11 @@ bool BabyMEG::start() bool BabyMEG::stop() { - requestInterruption(); - wait(2000); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } // Clear all data in the buffer connected to displays and other plugins m_pRTMSABabyMEG->measurementData()->clear(); @@ -260,13 +265,13 @@ void BabyMEG::run() { MatrixXf matValue; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { //pop matrix if(m_pCircularBuffer->pop(matValue)) { //Create digital trigger information createDigTrig(matValue); - if(!isInterruptionRequested()) { + if(m_bProcessOutput) { m_pRTMSABabyMEG->measurementData()->setValue(this->calibrate(matValue)); } } @@ -352,7 +357,7 @@ void BabyMEG::setFiffData(QByteArray data) IOUtils::swap_floatp(rawData.data()+i); } - if(this->isRunning()) { + if(m_bProcessOutput) { while(!m_pCircularBuffer->push(rawData)) { //Do nothing until the circular buffer is ready to accept new data again } diff --git a/src/applications/mne_scan/plugins/babymeg/babymeg.h b/src/applications/mne_scan/plugins/babymeg/babymeg.h index f91001fc508..ec492b173e4 100644 --- a/src/applications/mne_scan/plugins/babymeg/babymeg.h +++ b/src/applications/mne_scan/plugins/babymeg/babymeg.h @@ -50,6 +50,9 @@ #include #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -319,6 +322,8 @@ class BABYMEGSHARED_EXPORT BabyMEG : public SCSHAREDLIB::AbstractSensor QPointer m_pActionSqdCtrl; /**< show squid control. */ QPointer m_pActionUpdateFiffInfo; /**< Update Fiff Info action. */ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; signals: //========================================================================================================= /** diff --git a/src/applications/mne_scan/plugins/brainamp/brainamp.cpp b/src/applications/mne_scan/plugins/brainamp/brainamp.cpp index d3c5cc79056..6071e51eb31 100644 --- a/src/applications/mne_scan/plugins/brainamp/brainamp.cpp +++ b/src/applications/mne_scan/plugins/brainamp/brainamp.cpp @@ -84,6 +84,7 @@ BrainAMP::BrainAMP() , m_sRPA("2RD") , m_sNasion("0Z") , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_double(8))) +, m_bProcessOutput(false) { // Create record file option action bar item/button m_pActionSetupProject = new QAction(QIcon(":/images/database.png"), tr("Setup project"), this); @@ -99,7 +100,7 @@ BrainAMP::~BrainAMP() //std::cout << "BrainAMP::~BrainAMP() " << std::endl; //If the program is closed while the sampling is in process - if(this->isRunning()) { + if(m_bProcessOutput) { this->stop(); } } @@ -278,7 +279,8 @@ bool BrainAMP::start() m_iSamplingFreq); if(m_pBrainAMPProducer->isRunning()) { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&BrainAMP::run, this); return true; } else { qWarning() << "BrainAMP::start() - BrainAMPProducer thread could not be started." << endl; @@ -290,8 +292,11 @@ bool BrainAMP::start() bool BrainAMP::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } //Stop the producer thread first m_pBrainAMPProducer->stop(); @@ -372,7 +377,7 @@ void BrainAMP::run() { MatrixXd matData; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { if(m_pBrainAMPProducer->isRunning()) { //pop matrix if(m_pCircularBuffer->pop(matData)) { diff --git a/src/applications/mne_scan/plugins/brainamp/brainamp.h b/src/applications/mne_scan/plugins/brainamp/brainamp.h index 2e6f6e38557..7604b45e4f3 100644 --- a/src/applications/mne_scan/plugins/brainamp/brainamp.h +++ b/src/applications/mne_scan/plugins/brainamp/brainamp.h @@ -47,6 +47,9 @@ #include #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -232,6 +235,9 @@ protected slots: QAction* m_pActionSetupStimulus; /**< starts stimulus feature. */ QMutex m_mutex; + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.cpp b/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.cpp index 2ad9edad17e..03d46c4f7f3 100644 --- a/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.cpp +++ b/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.cpp @@ -69,6 +69,7 @@ BrainFlowBoard::BrainFlowBoard() , m_sStreamerParams("") , m_uiSamplesPerBlock(100) , m_pFiffInfo(QSharedPointer::create()) +, m_bProcessOutput(false) { m_pShowSettingsAction = new QAction(QIcon(":/images/options.png"), tr("Streaming Settings"),this); m_pShowSettingsAction->setStatusTip(tr("Streaming Settings")); @@ -244,7 +245,8 @@ bool BrainFlowBoard::start() msgBox.exec(); return false; } - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&BrainFlowBoard::run, this); return true; } @@ -256,8 +258,11 @@ bool BrainFlowBoard::stop() if(m_pBoardShim) { m_pBoardShim->stop_stream(); } - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_pOutput->measurementData()->clear(); } catch (const BrainFlowException &err) { BoardShim::log_message((int)LogLevels::LEVEL_ERROR, err.what()); @@ -388,12 +393,12 @@ void BrainFlowBoard::run() BrainFlowArray data; QList lSampleBlockBuffer; - while(!isInterruptionRequested()) { - usleep(lSamplingPeriod); + while(m_bProcessOutput) { + std::this_thread::sleep_for(std::chrono::microseconds(lSamplingPeriod)); iSampleIterator = 0; //get samples from device until the complete matrix is filled, i.e. the samples per block size is met - while(iSampleIterator < m_uiSamplesPerBlock && !isInterruptionRequested()) { + while(iSampleIterator < m_uiSamplesPerBlock && m_bProcessOutput) { //Get sample block from device data = m_pBoardShim->get_board_data (); if (data.get_size(1) == 0) { diff --git a/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.h b/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.h index 301fcfba8c3..7e9f7834bc1 100644 --- a/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.h +++ b/src/applications/mne_scan/plugins/brainflowboard/brainflowboard.h @@ -47,6 +47,10 @@ #include +#include +#include + + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -128,6 +132,9 @@ class BRAINFLOWBOARD_EXPORT BrainFlowBoard : public SCSHAREDLIB::AbstractSensor QSharedPointer > m_pOutput; QSharedPointer m_pFiffInfo; /**< Fiff measurement info.*/ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } diff --git a/src/applications/mne_scan/plugins/covariance/covariance.cpp b/src/applications/mne_scan/plugins/covariance/covariance.cpp index 842f28d6876..c1b22534675 100644 --- a/src/applications/mne_scan/plugins/covariance/covariance.cpp +++ b/src/applications/mne_scan/plugins/covariance/covariance.cpp @@ -82,6 +82,7 @@ using namespace Eigen; Covariance::Covariance() : m_iEstimationSamples(2000) , m_pCircularBuffer(CircularBuffer_Matrix_double::SPtr::create(40)) +, m_bProcessOutput(false) { } @@ -89,7 +90,7 @@ Covariance::Covariance() Covariance::~Covariance() { - if(this->isRunning()) + if(m_bProcessOutput) stop(); } @@ -158,7 +159,8 @@ void Covariance::unload() bool Covariance::start() { // Start thread - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&Covariance::run, this); return true; } @@ -167,8 +169,11 @@ bool Covariance::start() bool Covariance::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_bPluginControlWidgetsInit = false; @@ -249,7 +254,7 @@ void Covariance::run() break; } m_mutex.unlock(); - msleep(100); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } MatrixXd matData; @@ -260,7 +265,7 @@ void Covariance::run() RTPROCESSINGLIB::RtCov rtCov(m_pFiffInfo); // Start processing data - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { // Get the current data if(m_pCircularBuffer->pop(matData)) { m_mutex.lock(); diff --git a/src/applications/mne_scan/plugins/covariance/covariance.h b/src/applications/mne_scan/plugins/covariance/covariance.h index bb58b634d45..0494c59661d 100644 --- a/src/applications/mne_scan/plugins/covariance/covariance.h +++ b/src/applications/mne_scan/plugins/covariance/covariance.h @@ -45,6 +45,9 @@ #include #include +#include +#include + //============================================================================================================= // EIGEN INCLUDES //============================================================================================================= @@ -164,6 +167,9 @@ class COVARIANCESHARED_EXPORT Covariance : public SCSHAREDLIB::AbstractAlgorithm QSharedPointer > m_pCovarianceInput; /**< The RealTimeMultiSampleArray of the Covariance input.*/ QSharedPointer > m_pCovarianceOutput; /**< The RealTimeCov of the Covariance output.*/ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; + signals: }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/eegosports/eegosports.cpp b/src/applications/mne_scan/plugins/eegosports/eegosports.cpp index 5fabc6d341a..92bcd1d2133 100644 --- a/src/applications/mne_scan/plugins/eegosports/eegosports.cpp +++ b/src/applications/mne_scan/plugins/eegosports/eegosports.cpp @@ -98,6 +98,7 @@ EEGoSports::EEGoSports() , m_sRPA("2RD") , m_sNasion("0Z") , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_double(10))) +, m_bProcessOutput(false) { } @@ -106,7 +107,7 @@ EEGoSports::EEGoSports() EEGoSports::~EEGoSports() { //If the program is closed while the sampling is in process - if(this->isRunning()) { + if(m_bProcessOutput) { this->stop(); } } @@ -564,7 +565,8 @@ bool EEGoSports::start() m_bCheckImpedances); if(m_pEEGoSportsProducer->isRunning()) { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&EEGoSports::run, this);; return true; } else { qWarning() << "[EEGoSports::start] EEGoSports thread could not be started - Either the device is turned off (check your OS device manager) or the driver DLL (EEGO-SDK.dll) is not installed in one of the monitored dll path." << endl; @@ -577,8 +579,11 @@ bool EEGoSports::start() bool EEGoSports::stop() { // Stop this (consumer) thread first - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } //Stop the producer thread m_pEEGoSportsProducer->stop(); @@ -660,7 +665,7 @@ void EEGoSports::onUpdateCardinalPoints(const QString& sLPA, double dLPA, const void EEGoSports::showImpedanceDialog() { // Open Impedance dialog only if no sampling process is active - if(!this->isRunning()) { + if(!m_bProcessOutput) { if(m_pEEGoSportsImpedanceWidget == NULL) { m_pEEGoSportsImpedanceWidget = QSharedPointer(new EEGoSportsImpedanceWidget(this)); } @@ -700,7 +705,7 @@ void EEGoSports::run() { MatrixXd matData; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { if(m_pEEGoSportsProducer->isRunning()) { // Check impedances - send new impedance values to graphic scene if(m_bCheckImpedances) { diff --git a/src/applications/mne_scan/plugins/eegosports/eegosports.h b/src/applications/mne_scan/plugins/eegosports/eegosports.h index 075ab430e4a..5b4cdc7a4c4 100644 --- a/src/applications/mne_scan/plugins/eegosports/eegosports.h +++ b/src/applications/mne_scan/plugins/eegosports/eegosports.h @@ -53,6 +53,9 @@ #include #include +#include +#include + //============================================================================================================= // EIGEN INCLUDES //============================================================================================================= @@ -260,6 +263,9 @@ protected slots: QSharedPointer m_pEEGoSportsProducer; /**< The EEGoSportsProducer.*/ QMutex m_mutex; /**< Holds the threads mutex.*/ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.cpp b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.cpp index e09b7004867..5e4de948fd8 100644 --- a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.cpp +++ b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.cpp @@ -46,6 +46,7 @@ #include #include #include +#include //============================================================================================================= // QT INCLUDES @@ -56,6 +57,7 @@ #include #include #include +#include #include @@ -85,6 +87,8 @@ FiffSimulator::FiffSimulator() , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_float(40))) , m_pRtCmdClient(QSharedPointer::create()) , m_iDefaultPortCmdClient(4217) +, m_OutputProcessingThreadRunning(false) +, m_StopOutputProcessingThread(false) { //init channels when fiff info is available connect(this, &FiffSimulator::fiffInfoAvailable, @@ -95,7 +99,7 @@ FiffSimulator::FiffSimulator() FiffSimulator::~FiffSimulator() { - if(m_pFiffSimulatorProducer->isRunning() || this->isRunning()) { + if(m_pFiffSimulatorProducer->isRunning() || m_OutputProcessingThreadRunning) { stop(); } } @@ -148,13 +152,14 @@ bool FiffSimulator::start() m_pFiffSimulatorProducer->start(); // Wait one sec so the producer can update the m_iDataClientId accordingly - msleep(1000); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Start Measurement at mne_rt_server (*m_pRtCmdClient)["start"].pValues()[0].setValue(m_pFiffSimulatorProducer->m_iDataClientId); (*m_pRtCmdClient)["start"].send(); - QThread::start(); + m_OutputProcessingThread = std::thread(&FiffSimulator::run, this); + m_OutputProcessingThreadRunning = true; return true; } @@ -167,8 +172,11 @@ bool FiffSimulator::start() bool FiffSimulator::stop() { // Stop this (consumer) thread first - requestInterruption(); - wait(500); + m_StopOutputProcessingThread = true; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } // Stop producer thread second m_pFiffSimulatorProducer->stop(); @@ -182,6 +190,8 @@ bool FiffSimulator::stop() m_pRTMSA_FiffSimulator->measurementData()->clear(); m_pCircularBuffer->clear(); + m_StopOutputProcessingThread = false; + return true; } @@ -214,11 +224,11 @@ void FiffSimulator::run() { MatrixXf matValue; - while(!isInterruptionRequested()) { + while(!m_StopOutputProcessingThread) { //pop matrix if(m_pCircularBuffer->pop(matValue)) { //emit values - if(!isInterruptionRequested()) { + if(!m_StopOutputProcessingThread) { m_pRTMSA_FiffSimulator->measurementData()->setValue(matValue.cast()); } } diff --git a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.h b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.h index 0f734b64421..bd740a877bd 100644 --- a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.h +++ b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulator.h @@ -45,6 +45,8 @@ #include #include #include +#include +#include //============================================================================================================= // QT INCLUDES @@ -212,6 +214,10 @@ class FIFFSIMULATORSHARED_EXPORT FiffSimulator : public SCSHAREDLIB::AbstractSen QMutex m_qMutex; /**< The mutex to ensure thread safety.*/ + std::thread m_OutputProcessingThread; + std::atomic_bool m_OutputProcessingThreadRunning; + std::atomic_bool m_StopOutputProcessingThread; + signals: //========================================================================================================= /** diff --git a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulatorproducer.cpp b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulatorproducer.cpp index 94565a172c0..f523fc326eb 100644 --- a/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulatorproducer.cpp +++ b/src/applications/mne_scan/plugins/fiffsimulator/fiffsimulatorproducer.cpp @@ -178,7 +178,7 @@ void FiffSimulatorProducer::run() m_producerMutex.unlock(); // Only perform data reading if the measurement was started - if(m_pFiffSimulator->isRunning()) { + if(m_pFiffSimulator->m_OutputProcessingThreadRunning) { m_pRtDataClient->readRawBuffer(m_pFiffSimulator->m_pFiffInfo->nchan, matData, kind); diff --git a/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.cpp b/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.cpp index 27373683103..9eeb9e8bf38 100644 --- a/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.cpp +++ b/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.cpp @@ -70,6 +70,7 @@ FtBuffer::FtBuffer() , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_double(10))) , m_sBufferAddress("127.0.0.1") , m_iBufferPort(1972) +, m_bProcessOutput(false) { } @@ -133,7 +134,8 @@ bool FtBuffer::start() qInfo() << "[FtBuffer::start] Producer thread created, sending work command..."; emit workCommand(); - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&FtBuffer::run, this); return true; } @@ -146,14 +148,17 @@ bool FtBuffer::stop() m_bIsConfigured = false; - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } //stops separate producer/client thread first m_pProducerThread.requestInterruption(); int itries = 0; while(m_pProducerThread.isRunning()) { - msleep(10); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); if(itries > 10){ break; } @@ -200,12 +205,12 @@ void FtBuffer::run() { MatrixXd matData; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { //qDebug() << "[FtBuffer::run] m_pFiffInfo->dig.size()" << m_pFiffInfo->dig.size(); //pop matrix if(m_pCircularBuffer->pop(matData)) { //emit values - if(!isInterruptionRequested()) { + if(m_bProcessOutput) { m_pRTMSA_BufferOutput->measurementData()->setValue(matData); } } diff --git a/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.h b/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.h index 1fee9b457ef..d196a863833 100644 --- a/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.h +++ b/src/applications/mne_scan/plugins/ftbuffer/ftbuffer.h @@ -55,6 +55,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -253,6 +256,9 @@ class FTBUFFER_EXPORT FtBuffer : public SCSHAREDLIB::AbstractSensor QString m_sBufferAddress; /**< The address used to connect to the buffer if starting without being connected */ int m_iBufferPort; /**< The port used to connect to the buffer if starting without being connected */ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; }//namespace end brace diff --git a/src/applications/mne_scan/plugins/gusbamp/gusbamp.cpp b/src/applications/mne_scan/plugins/gusbamp/gusbamp.cpp index 47eacf012cb..b26b4a88f15 100644 --- a/src/applications/mne_scan/plugins/gusbamp/gusbamp.cpp +++ b/src/applications/mne_scan/plugins/gusbamp/gusbamp.cpp @@ -72,6 +72,7 @@ GUSBAmp::GUSBAmp() , m_iSamplesPerBlock(0) , m_iSampleRate(128) , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_float(8))) +, m_bProcessOutput(false) { m_viChannelsToAcquire = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; @@ -86,7 +87,7 @@ GUSBAmp::GUSBAmp() GUSBAmp::~GUSBAmp() { //If the program is closed while the sampling is in process - if(this->isRunning()){ + if(m_bProcessOutput){ this->stop(); } } @@ -212,7 +213,8 @@ bool GUSBAmp::start() //start the thread for ring buffer if(m_pGUSBAmpProducer->isRunning()) { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&GUSBAmp::run, this); return true; } else { qWarning() << "Plugin GUSBAmp - ERROR - GUSBAmpProducer thread could not be started - Either the device is turned off (check your OS device manager) or the driver DLL (GUSBAmpSDK.dll / GUSBAmpSDK32bit.dll) is not installed in the system32 / SysWOW64 directory" << endl; @@ -225,8 +227,11 @@ bool GUSBAmp::start() bool GUSBAmp::stop() { // Stop this (consumer) thread first - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } //Stop the producer thread first m_pGUSBAmpProducer->stop(); @@ -271,7 +276,7 @@ void GUSBAmp::run() qint32 size = 0; MatrixXf matValue; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { //pop matrix only if the producer thread is running if(m_pGUSBAmpProducer->isRunning()) { //pop matrix diff --git a/src/applications/mne_scan/plugins/gusbamp/gusbamp.h b/src/applications/mne_scan/plugins/gusbamp/gusbamp.h index 7f749e7408c..2bffd9efcc9 100644 --- a/src/applications/mne_scan/plugins/gusbamp/gusbamp.h +++ b/src/applications/mne_scan/plugins/gusbamp/gusbamp.h @@ -50,6 +50,9 @@ #include "FormFiles/gusbampsetupwidget.h" #include "FormFiles/gusbampsetupprojectwidget.h" +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -211,6 +214,9 @@ class GUSBAMPSHARED_EXPORT GUSBAmp : public SCSHAREDLIB::AbstractSensor std::vector m_viSizeOfSampleMatrix; /**< vector including the size of the two dimensional sample Matrix. */ std::vector m_viChannelsToAcquire; /**< vector of the calling numbers of the channels to be acquired. */ Eigen::RowVectorXd m_cals; + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/hpi/hpi.cpp b/src/applications/mne_scan/plugins/hpi/hpi.cpp index c3b2f975b50..4e6ed735f5d 100644 --- a/src/applications/mne_scan/plugins/hpi/hpi.cpp +++ b/src/applications/mne_scan/plugins/hpi/hpi.cpp @@ -97,6 +97,7 @@ Hpi::Hpi() , m_bUseSSP(false) , m_bUseComp(false) , m_pCircularBuffer(CircularBuffer_Matrix_double::SPtr::create(40)) +, m_bProcessOutput(false) { connect(this, &Hpi::devHeadTransAvailable, this, &Hpi::onDevHeadTransAvailable, Qt::BlockingQueuedConnection); @@ -106,8 +107,8 @@ Hpi::Hpi() Hpi::~Hpi() { - if(isRunning()) { - resetState(); + if(m_bProcessOutput) { + stop(); } } @@ -145,7 +146,9 @@ void Hpi::unload() bool Hpi::start() { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&Hpi::run, this); + return true; } @@ -154,7 +157,11 @@ bool Hpi::start() bool Hpi::stop() { - requestInterruption(); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } resetState(); return true; } @@ -545,7 +552,7 @@ void Hpi::run() if(bFiffInfo) { break; } - msleep(100); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } // init hpi fit @@ -583,7 +590,7 @@ void Hpi::run() MatrixXd matDataMerged(m_pFiffInfo->chs.size(), fittingWindowSize); bool bOrder = false; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { m_mutex.lock(); if(fittingWindowSize != m_iFittingWindowSize) { fittingWindowSize = m_iFittingWindowSize; diff --git a/src/applications/mne_scan/plugins/hpi/hpi.h b/src/applications/mne_scan/plugins/hpi/hpi.h index 83b0f332ab9..00ba80075a5 100644 --- a/src/applications/mne_scan/plugins/hpi/hpi.h +++ b/src/applications/mne_scan/plugins/hpi/hpi.h @@ -47,6 +47,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -320,6 +323,9 @@ class HPISHARED_EXPORT Hpi : public SCSHAREDLIB::AbstractAlgorithm SCSHAREDLIB::PluginInputData::SPtr m_pHpiInput; /**< The RealTimeMultiSampleArray of the Hpi input.*/ SCSHAREDLIB::PluginOutputData::SPtr m_pHpiOutput; /**< The RealTimeHpiResult of the Hpi output.*/ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; + signals: void errorsChanged(const QVector& vErrors, double dMeanErrorDist); diff --git a/src/applications/mne_scan/plugins/natus/natus.cpp b/src/applications/mne_scan/plugins/natus/natus.cpp index 33c058202c7..9aa65e6c299 100644 --- a/src/applications/mne_scan/plugins/natus/natus.cpp +++ b/src/applications/mne_scan/plugins/natus/natus.cpp @@ -75,6 +75,7 @@ Natus::Natus() , m_qStringResourcePath(qApp->applicationDirPath()+"/../resources/mne_scan/plugins/natus/") , m_pRMTSA_Natus(PluginOutputData::create(this, "Natus", "EEG output data")) , m_pFiffInfo(QSharedPointer::create()) +, m_bProcessOutput(false) { m_pRMTSA_Natus->measurementData()->setName(this->getName());//Provide name to auto store widget settings } @@ -84,7 +85,7 @@ Natus::Natus() Natus::~Natus() { //If the program is closed while the sampling is in process - if(this->isRunning()) { + if(m_bProcessOutput) { this->stop(); } } @@ -229,7 +230,8 @@ bool Natus::start() m_pRMTSA_Natus->measurementData()->initFromFiffInfo(m_pFiffInfo); m_pRMTSA_Natus->measurementData()->setMultiArraySize(1); - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&Natus::run, this); // Start the producer m_pNatusProducer = QSharedPointer::create(m_iSamplesPerBlock, m_iNumberChannels); @@ -245,8 +247,11 @@ bool Natus::start() bool Natus::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } // Clear all data in the buffer connected to displays and other plugins m_pRMTSA_Natus->measurementData()->clear(); @@ -299,10 +304,10 @@ void Natus::run() { MatrixXd matData; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { if(m_pCircularBuffer->pop(matData)) { //emit values - if(!isInterruptionRequested()) { + if(m_bProcessOutput) { m_pRMTSA_Natus->measurementData()->setValue(matData); } } diff --git a/src/applications/mne_scan/plugins/natus/natus.h b/src/applications/mne_scan/plugins/natus/natus.h index 5621a186e45..30cc33a0270 100644 --- a/src/applications/mne_scan/plugins/natus/natus.h +++ b/src/applications/mne_scan/plugins/natus/natus.h @@ -44,12 +44,16 @@ #include #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= #include #include +#include //============================================================================================================= // EIGEN INCLUDES @@ -181,6 +185,9 @@ class NATUSSHARED_EXPORT Natus : public SCSHAREDLIB::AbstractSensor QSharedPointer > m_pRMTSA_Natus; /**< The RealTimeSampleArray to provide the EEG data.*/ QSharedPointer m_pFiffInfo; /**< Fiff measurement info.*/ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.cpp b/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.cpp index 9a2aa749cbe..e31cccefb16 100644 --- a/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.cpp +++ b/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.cpp @@ -95,6 +95,7 @@ NeuronalConnectivity::NeuronalConnectivity() , m_pCircularBuffer(CircularBuffer::SPtr::create(40)) , m_pRtConnectivity(RtConnectivity::SPtr::create()) , m_pActionShowYourWidget(Q_NULLPTR) +, m_bProcessOutput(false) { AbstractMetric::m_bStorageModeIsActive = true; AbstractMetric::m_iNumberBinStart = 0; @@ -109,7 +110,7 @@ NeuronalConnectivity::NeuronalConnectivity() NeuronalConnectivity::~NeuronalConnectivity() { - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } } @@ -195,7 +196,8 @@ void NeuronalConnectivity::unload() bool NeuronalConnectivity::start() { //Start thread - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&NeuronalConnectivity::run, this); return true; } @@ -206,8 +208,11 @@ bool NeuronalConnectivity::stop() { m_pRtConnectivity->restart(); - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_bPluginControlWidgetsInit = false; @@ -510,13 +515,13 @@ void NeuronalConnectivity::run() break; } m_mutex.unlock(); - msleep(100); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } int skip_count = 0; Network network; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { //Do processing after skip count has reached limit if((skip_count % m_iDownSample) == 0) { if(m_pCircularBuffer->pop(network)) { @@ -562,7 +567,7 @@ void NeuronalConnectivity::onMetricChanged(const QString& sMetric) m_sConnectivityMethods = QStringList() << sMetric; m_connectivitySettings.setConnectivityMethods(m_sConnectivityMethods); - if(m_pRtConnectivity && this->isRunning()) { + if(m_pRtConnectivity && m_bProcessOutput) { m_pRtConnectivity->restart(); m_pRtConnectivity->append(m_connectivitySettings); } diff --git a/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.h b/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.h index 4d97e087ba0..7b3f5ece529 100644 --- a/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.h +++ b/src/applications/mne_scan/plugins/neuronalconnectivity/neuronalconnectivity.h @@ -49,6 +49,9 @@ #include #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -272,6 +275,9 @@ class NEURONALCONNECTIVITYSHARED_EXPORT NeuronalConnectivity : public SCSHAREDLI Eigen::RowVectorXi m_vecPicks; /**< The picked data channels. */ CONNECTIVITYLIB::Network m_currentConnectivityResult; /**< The current connectivity result.*/ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/noisereduction/noisereduction.cpp b/src/applications/mne_scan/plugins/noisereduction/noisereduction.cpp index 92882f69f60..e1f2471bbc8 100644 --- a/src/applications/mne_scan/plugins/noisereduction/noisereduction.cpp +++ b/src/applications/mne_scan/plugins/noisereduction/noisereduction.cpp @@ -93,6 +93,7 @@ NoiseReduction::NoiseReduction() , m_pCircularBuffer(QSharedPointer::create(40)) , m_pNoiseReductionInput(Q_NULLPTR) , m_pNoiseReductionOutput(Q_NULLPTR) +, m_bProcessOutput(false) { if(m_sCurrentSystem == "BabyMEG") { m_iNBaseFctsFirst = 270; @@ -111,7 +112,7 @@ NoiseReduction::NoiseReduction() NoiseReduction::~NoiseReduction() { - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } } @@ -159,8 +160,11 @@ bool NoiseReduction::start() bool NoiseReduction::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_iMaxFilterTapSize = -1; @@ -224,7 +228,8 @@ void NoiseReduction::update(SCMEASLIB::Measurement::SPtr pMeasurement) if(m_iMaxFilterTapSize == -1) { m_iMaxFilterTapSize = pRTMSA->getMultiSampleArray().first().cols(); initPluginControlWidgets(); - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&NoiseReduction::run, this); } for(unsigned char i = 0; i < pRTMSA->getMultiSampleArray().size(); ++i) { @@ -345,7 +350,7 @@ void NoiseReduction::run() MatrixXd matData; QScopedPointer pRtFilter(new RTPROCESSINGLIB::FilterOverlapAdd()); - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { // Get the current data if(m_pCircularBuffer->pop(matData)) { m_mutex.lock(); @@ -409,7 +414,7 @@ void NoiseReduction::run() m_mutex.unlock(); //Send the data to the connected plugins and the display - if(!isInterruptionRequested()) { + if(m_bProcessOutput) { m_pNoiseReductionOutput->measurementData()->setValue(matData); } } diff --git a/src/applications/mne_scan/plugins/noisereduction/noisereduction.h b/src/applications/mne_scan/plugins/noisereduction/noisereduction.h index e6e6c0dc2cd..1c5c2cd23ce 100644 --- a/src/applications/mne_scan/plugins/noisereduction/noisereduction.h +++ b/src/applications/mne_scan/plugins/noisereduction/noisereduction.h @@ -50,6 +50,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -263,6 +266,8 @@ class NOISEREDUCTIONSHARED_EXPORT NoiseReduction : public SCSHAREDLIB::AbstractA SCSHAREDLIB::PluginInputData::SPtr m_pNoiseReductionInput; /**< The RealTimeMultiSampleArray of the NoiseReduction input.*/ SCSHAREDLIB::PluginOutputData::SPtr m_pNoiseReductionOutput; /**< The RealTimeMultiSampleArray of the NoiseReduction output.*/ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; signals: }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/rtcmne/rtcmne.cpp b/src/applications/mne_scan/plugins/rtcmne/rtcmne.cpp index 6c8a43e16de..4ecaf16d393 100644 --- a/src/applications/mne_scan/plugins/rtcmne/rtcmne.cpp +++ b/src/applications/mne_scan/plugins/rtcmne/rtcmne.cpp @@ -106,6 +106,7 @@ RtcMne::RtcMne() , m_sMethod("dSPM") , m_fMriHeadTrans(QCoreApplication::applicationDirPath() + "/../resources/data/MNE-sample-data/MEG/sample/all-trans.fif") , m_bUpdateMinimumNorm(false) +, m_bProcessOutput(false) { } @@ -115,7 +116,7 @@ RtcMne::~RtcMne() { m_future.waitForFinished(); - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } } @@ -313,7 +314,8 @@ bool RtcMne::calcFiffInfo() bool RtcMne::start() { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&RtcMne::run, this); return true; } @@ -321,8 +323,11 @@ bool RtcMne::start() bool RtcMne::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_qListCovChNames.clear(); m_bEvokedInput = false; @@ -369,7 +374,7 @@ void RtcMne::updateRTFS(SCMEASLIB::Measurement::SPtr pMeasurement) m_qMutex.unlock(); // update inverse operator - if(this->isRunning() && m_pRtInvOp) { + if(m_bProcessOutput && m_pRtInvOp) { m_pRtInvOp->setFwdSolution(m_pFwd); m_pRtInvOp->append(*m_pNoiseCov); } @@ -386,7 +391,7 @@ void RtcMne::updateRTMSA(SCMEASLIB::Measurement::SPtr pMeasurement) if(m_pFwd) { QSharedPointer pRTMSA = pMeasurement.dynamicCast(); - if(pRTMSA && this->isRunning()) { + if(pRTMSA && m_bProcessOutput) { //Fiff Information of the RTMSA m_qMutex.lock(); if(!m_pFiffInfoInput) { @@ -400,7 +405,7 @@ void RtcMne::updateRTMSA(SCMEASLIB::Measurement::SPtr pMeasurement) initPluginControlWidgets(); } - if(this->isRunning()) { + if(m_bProcessOutput) { // Check for artifacts QMap mapReject; mapReject.insert("eog", 150e-06); @@ -433,7 +438,7 @@ void RtcMne::updateRTC(SCMEASLIB::Measurement::SPtr pMeasurement) if(m_pFwd) { QSharedPointer pRTC = pMeasurement.dynamicCast(); - if(pRTC && this->isRunning()) { + if(pRTC && m_bProcessOutput) { // Init Real-Time inverse estimator if(!m_pRtInvOp && m_pFiffInfo && m_pFwd) { m_pRtInvOp = RtInvOp::SPtr(new RtInvOp(m_pFiffInfo, m_pFwd)); @@ -446,7 +451,7 @@ void RtcMne::updateRTC(SCMEASLIB::Measurement::SPtr pMeasurement) m_qListCovChNames = pRTC->getValue()->names; } - if(this->isRunning() && m_pRtInvOp){ + if(m_bProcessOutput && m_pRtInvOp){ m_pNoiseCov = pRTC->getValue(); m_pRtInvOp->append(*m_pNoiseCov); } @@ -467,7 +472,7 @@ void RtcMne::updateRTE(SCMEASLIB::Measurement::SPtr pMeasurement) initPluginControlWidgets(); } - if(!this->isRunning() || !lResponsibleTriggerTypes.contains(m_sAvrType)) { + if(!m_bProcessOutput || !lResponsibleTriggerTypes.contains(m_sAvrType)) { return; } @@ -491,7 +496,7 @@ void RtcMne::updateRTE(SCMEASLIB::Measurement::SPtr pMeasurement) initPluginControlWidgets(); } - if(this->isRunning()) { + if(m_bProcessOutput) { for(int i = 0; i < pFiffEvokedSet->evoked.size(); ++i) { if(pFiffEvokedSet->evoked.at(i).comment == m_sAvrType) { // Store current evoked as member so we can dispatch it if the time pick by the user changed @@ -551,7 +556,7 @@ void RtcMne::onTimePointValueChanged(int iTimePointMs) m_iTimePointSps = m_pFiffInfoInput->sfreq * (float)iTimePointMs * 0.001f; m_qMutex.unlock(); - if(this->isRunning()) { + if(m_bProcessOutput) { while(!m_pCircularEvokedBuffer->push(m_currentEvoked)) { //Do nothing until the circular buffer is ready to accept new data again } @@ -565,7 +570,7 @@ void RtcMne::run() { // Wait for fiff info to arrive while(!calcFiffInfo()) { - msleep(200); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } // Init parameters @@ -588,7 +593,7 @@ void RtcMne::run() QStringList lChNamesInvOp; // Start processing data - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { m_qMutex.lock(); iTimePointSps = m_iTimePointSps; bEvokedInput = m_bEvokedInput; diff --git a/src/applications/mne_scan/plugins/rtcmne/rtcmne.h b/src/applications/mne_scan/plugins/rtcmne/rtcmne.h index 83c36037120..289862070d6 100644 --- a/src/applications/mne_scan/plugins/rtcmne/rtcmne.h +++ b/src/applications/mne_scan/plugins/rtcmne/rtcmne.h @@ -50,6 +50,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -265,6 +268,9 @@ class RTCMNESHARED_EXPORT RtcMne : public SCSHAREDLIB::AbstractAlgorithm MNELIB::MNEInverseOperator m_invOp; /**< The inverse operator. */ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; + signals: void responsibleTriggerTypesChanged(const QStringList& lResponsibleTriggerTypes); diff --git a/src/applications/mne_scan/plugins/rtfwd/rtfwd.cpp b/src/applications/mne_scan/plugins/rtfwd/rtfwd.cpp index aa9ddf85461..fc3fcd97f15 100644 --- a/src/applications/mne_scan/plugins/rtfwd/rtfwd.cpp +++ b/src/applications/mne_scan/plugins/rtfwd/rtfwd.cpp @@ -92,6 +92,7 @@ RtFwd::RtFwd() , m_bDoRecomputation(false) , m_bDoClustering(true) , m_bDoFwdComputation(false) +, m_bProcessOutput(false) { // set init values m_pFwdSettings->solname = QCoreApplication::applicationDirPath() + "/../resources/data/MNE-sample-data/your-solution-fwd.fif"; @@ -115,7 +116,7 @@ RtFwd::~RtFwd() { m_future.waitForFinished(); - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } } @@ -222,7 +223,8 @@ bool RtFwd::start() stream->close(); //Start thread - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&RtFwd::run, this); return true; } @@ -231,8 +233,11 @@ bool RtFwd::start() bool RtFwd::stop() { - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_bPluginControlWidgetsInit = false; @@ -400,7 +405,7 @@ void RtFwd::run() break; } m_mutex.unlock(); - msleep(200); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } m_mutex.lock(); @@ -429,7 +434,7 @@ void RtFwd::run() bool bDoFwdComputation = false; // compute forward if requested bool bIsInit = false; // only recompute if initial fwd solulion is calculated - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { m_mutex.lock(); bDoFwdComputation = m_bDoFwdComputation; m_mutex.unlock(); diff --git a/src/applications/mne_scan/plugins/rtfwd/rtfwd.h b/src/applications/mne_scan/plugins/rtfwd/rtfwd.h index f92c168b13a..c2609569f8b 100644 --- a/src/applications/mne_scan/plugins/rtfwd/rtfwd.h +++ b/src/applications/mne_scan/plugins/rtfwd/rtfwd.h @@ -49,6 +49,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -224,6 +227,9 @@ class RTFWDSHARED_EXPORT RtFwd : public SCSHAREDLIB::AbstractAlgorithm SCSHAREDLIB::PluginOutputData::SPtr m_pRTFSOutput; /**< The fwd solution.*/ + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; + signals: //========================================================================================================= /** diff --git a/src/applications/mne_scan/plugins/tmsi/tmsi.cpp b/src/applications/mne_scan/plugins/tmsi/tmsi.cpp index e3ff333a2aa..fd4e4ba1481 100644 --- a/src/applications/mne_scan/plugins/tmsi/tmsi.cpp +++ b/src/applications/mne_scan/plugins/tmsi/tmsi.cpp @@ -70,6 +70,7 @@ TMSI::TMSI() , m_qStringResourcePath(qApp->applicationDirPath()+"/../resources/mne_scan/plugins/tmsi/") , m_pTMSIProducer(new TMSIProducer(this)) , m_pCircularBuffer(QSharedPointer(new CircularBuffer_Matrix_float(8))) +, m_bProcessOutput(false) { // Create record file option action bar item/button m_pActionSetupProject = new QAction(QIcon(":/images/database.png"), tr("Setup project"), this); @@ -89,7 +90,7 @@ TMSI::TMSI() TMSI::~TMSI() { //If the program is closed while the sampling is in process - if(this->isRunning()) { + if(m_bProcessOutput) { this->stop(); } } @@ -485,7 +486,7 @@ bool TMSI::start() m_bWriteDriverDebugToFile, m_bUseCommonAverage, m_bCheckImpedances); - wait(500); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); if(m_pTMSIProducer->isRunning()) { // Init BCIFeatureWindow for visualization @@ -496,7 +497,8 @@ bool TMSI::start() m_pTmsiManualAnnotationWidget->show(); } - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&TMSI::run, this); return true; } else { qWarning() << "[TMSI::start] TMSIProducer thread could not be started - Either the device is turned off (check your OS device manager) or the driver DLL (TMSiSDK.dll / TMSiSDK32bit.dll) is not installed in the system32 / SysWOW64 directory" << endl; @@ -512,8 +514,11 @@ bool TMSI::stop() m_pTMSIProducer->stop(); //Wait until this thread (TMSI) is stopped - requestInterruption(); - wait(500); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } // Clear all data in the buffer connected to displays and other plugins m_pRMTSA_TMSI->measurementData()->clear(); @@ -568,7 +573,7 @@ void TMSI::run() qint32 size = 0; MatrixXf matData; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { // Check impedances - send new impedance values to graphic scene if(m_pTMSIProducer->isRunning() && m_bCheckImpedances) { if(m_pCircularBuffer->pop(matData)) { @@ -629,7 +634,7 @@ void TMSI::run() void TMSI::showImpedanceDialog() { // Open Impedance dialog only if no sampling process is active - if(!this->isRunning()) { + if(!m_bProcessOutput) { if(m_pTmsiImpedanceWidget == NULL) { m_pTmsiImpedanceWidget = QSharedPointer(new TMSIImpedanceWidget(this)); } diff --git a/src/applications/mne_scan/plugins/tmsi/tmsi.h b/src/applications/mne_scan/plugins/tmsi/tmsi.h index e5ddb09db51..4c1fdce616d 100644 --- a/src/applications/mne_scan/plugins/tmsi/tmsi.h +++ b/src/applications/mne_scan/plugins/tmsi/tmsi.h @@ -60,6 +60,9 @@ #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -254,6 +257,9 @@ class TMSISHARED_EXPORT TMSI : public SCSHAREDLIB::AbstractSensor QAction* m_pActionImpedance; /**< shows impedance widget. */ QAction* m_pActionSetupProject; /**< shows setup project dialog. */ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE diff --git a/src/applications/mne_scan/plugins/writetofile/writetofile.cpp b/src/applications/mne_scan/plugins/writetofile/writetofile.cpp index 3b8f7f72b60..bb7a51fc1b8 100644 --- a/src/applications/mne_scan/plugins/writetofile/writetofile.cpp +++ b/src/applications/mne_scan/plugins/writetofile/writetofile.cpp @@ -78,6 +78,7 @@ WriteToFile::WriteToFile() , m_iSplitCount(0) , m_iRecordingMSeconds(5*60*1000) , m_pCircularBuffer(CircularBuffer_Matrix_double::SPtr(new CircularBuffer_Matrix_double(40))) +, m_bProcessOutput(false) { m_pActionRecordFile = new QAction(QIcon(":/images/record.png"), tr("Start Recording"),this); m_pActionRecordFile->setStatusTip(tr("Start Recording")); @@ -111,7 +112,7 @@ WriteToFile::WriteToFile() WriteToFile::~WriteToFile() { - if(this->isRunning()) { + if(m_bProcessOutput) { stop(); } } @@ -145,7 +146,8 @@ void WriteToFile::unload() bool WriteToFile::start() { - QThread::start(); + m_bProcessOutput = true; + m_OutputProcessingThread = std::thread(&WriteToFile::run, this); return true; } @@ -154,8 +156,11 @@ bool WriteToFile::start() bool WriteToFile::stop() { - requestInterruption(); - wait(); + m_bProcessOutput = false; + + if(m_OutputProcessingThread.joinable()){ + m_OutputProcessingThread.join(); + } m_bPluginControlWidgetsInit = false; @@ -293,7 +298,7 @@ void WriteToFile::run() MatrixXd matData; qint32 size = 0; - while(!isInterruptionRequested()) { + while(m_bProcessOutput) { if(m_pCircularBuffer) { //pop matrix diff --git a/src/applications/mne_scan/plugins/writetofile/writetofile.h b/src/applications/mne_scan/plugins/writetofile/writetofile.h index 1530c89d7b7..3246aa0c143 100644 --- a/src/applications/mne_scan/plugins/writetofile/writetofile.h +++ b/src/applications/mne_scan/plugins/writetofile/writetofile.h @@ -46,6 +46,9 @@ #include #include +#include +#include + //============================================================================================================= // QT INCLUDES //============================================================================================================= @@ -310,6 +313,9 @@ class WRITETOFILESHARED_EXPORT WriteToFile : public SCSHAREDLIB::AbstractAlgorit FIFFLIB::FiffFileSharer m_FileSharer; /**< Handles copying recording file and saving copy to shared directory. */ QStringList m_lFileNames; /**< List of file names of latest recording */ + + std::thread m_OutputProcessingThread; + std::atomic_bool m_bProcessOutput; }; } // NAMESPACE