diff options
author | Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl> | 2019-08-14 11:45:34 +0200 |
---|---|---|
committer | Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl> | 2019-08-14 11:45:34 +0200 |
commit | d9261bdb05cd0863a2c3747c812871dbb851646e (patch) | |
tree | d1a81110e3fe213747a58f236e021a085417f663 | |
parent | 9a58b7451179ed512f975bc4c90fb71f172250b9 (diff) | |
download | astra-d9261bdb05cd0863a2c3747c812871dbb851646e.tar.gz astra-d9261bdb05cd0863a2c3747c812871dbb851646e.tar.bz2 astra-d9261bdb05cd0863a2c3747c812871dbb851646e.tar.xz astra-d9261bdb05cd0863a2c3747c812871dbb851646e.zip |
Replace signal-based abort handling by query-based handling
The abort handling is currently only used to process Ctrl-C from Matlab.
Since Matlab R2019a, it appears that calling utIsInterruptPending() from
a thread other than the main thread will crash. The previous approach of
checking utIsInterruptPending() in a thread, and then signalling the running
algorithm was therefore broken.
28 files changed, 48 insertions, 188 deletions
diff --git a/cuda/2d/algo.cu b/cuda/2d/algo.cu index f809c23..b4c2864 100644 --- a/cuda/2d/algo.cu +++ b/cuda/2d/algo.cu @@ -42,7 +42,6 @@ ReconAlgo::ReconAlgo() { parProjs = 0; fanProjs = 0; - shouldAbort = false; useVolumeMask = false; useSinogramMask = false; @@ -77,7 +76,6 @@ void ReconAlgo::reset() parProjs = 0; fanProjs = 0; - shouldAbort = false; useVolumeMask = false; useSinogramMask = false; diff --git a/cuda/2d/cgls.cu b/cuda/2d/cgls.cu index 696a0c1..b6a9fae 100644 --- a/cuda/2d/cgls.cu +++ b/cuda/2d/cgls.cu @@ -114,8 +114,6 @@ bool CGLS::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, f bool CGLS::iterate(unsigned int iterations) { - shouldAbort = false; - if (!sliceInitialized) { // copy sinogram @@ -146,7 +144,7 @@ bool CGLS::iterate(unsigned int iterations) // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { // w = A*p zeroProjectionData(D_w, wPitch, dims); diff --git a/cuda/2d/em.cu b/cuda/2d/em.cu index ca09d31..aa272d8 100644 --- a/cuda/2d/em.cu +++ b/cuda/2d/em.cu @@ -117,15 +117,13 @@ bool EM::precomputeWeights() bool EM::iterate(unsigned int iterations) { - shouldAbort = false; - #if 0 if (useVolumeMask) precomputeWeights(); #endif // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { // Do FP of volumeData zeroProjectionData(D_projData, projPitch, dims); diff --git a/cuda/2d/sart.cu b/cuda/2d/sart.cu index cf9babc..64973ba 100644 --- a/cuda/2d/sart.cu +++ b/cuda/2d/sart.cu @@ -166,13 +166,11 @@ bool SART::precomputeWeights() bool SART::iterate(unsigned int iterations) { - shouldAbort = false; - if (useVolumeMask) precomputeWeights(); // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { int angle; if (customOrder) { diff --git a/cuda/2d/sirt.cu b/cuda/2d/sirt.cu index 7ec377c..2621490 100644 --- a/cuda/2d/sirt.cu +++ b/cuda/2d/sirt.cu @@ -238,13 +238,11 @@ bool SIRT::uploadMinMaxMasks(const float* pfMinMaskData, const float* pfMaxMaskD bool SIRT::iterate(unsigned int iterations) { - shouldAbort = false; - if (useVolumeMask || useSinogramMask) precomputeWeights(); // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { // copy sinogram to projection data duplicateProjectionData(D_projData, D_sinoData, projPitch, dims); diff --git a/cuda/3d/algo3d.cu b/cuda/3d/algo3d.cu index b4a435b..3a83194 100644 --- a/cuda/3d/algo3d.cu +++ b/cuda/3d/algo3d.cu @@ -39,7 +39,6 @@ ReconAlgo3D::ReconAlgo3D() { coneProjs = 0; par3DProjs = 0; - shouldAbort = false; } ReconAlgo3D::~ReconAlgo3D() @@ -53,7 +52,6 @@ void ReconAlgo3D::reset() coneProjs = 0; delete[] par3DProjs; par3DProjs = 0; - shouldAbort = false; } bool ReconAlgo3D::setConeGeometry(const SDimensions3D& _dims, const SConeProjection* _angles, const SProjectorParams3D& _params) diff --git a/cuda/3d/astra3d.cu b/cuda/3d/astra3d.cu index be258be..51e76cd 100644 --- a/cuda/3d/astra3d.cu +++ b/cuda/3d/astra3d.cu @@ -625,14 +625,6 @@ bool AstraSIRT3d::getReconstruction(float* pfReconstruction, return true; } -void AstraSIRT3d::signalAbort() -{ - if (!pData->initialized) - return; - - pData->sirt.signalAbort(); -} - float AstraSIRT3d::computeDiffNorm() { if (!pData->initialized) @@ -1006,14 +998,6 @@ bool AstraCGLS3d::getReconstruction(float* pfReconstruction, return true; } -void AstraCGLS3d::signalAbort() -{ - if (!pData->initialized) - return; - - pData->cgls.signalAbort(); -} - float AstraCGLS3d::computeDiffNorm() { if (!pData->initialized) diff --git a/cuda/3d/cgls3d.cu b/cuda/3d/cgls3d.cu index 0df10f0..10c5f1e 100644 --- a/cuda/3d/cgls3d.cu +++ b/cuda/3d/cgls3d.cu @@ -146,8 +146,6 @@ bool CGLS::setBuffers(cudaPitchedPtr& _D_volumeData, bool CGLS::iterate(unsigned int iterations) { - shouldAbort = false; - if (!sliceInitialized) { // copy sinogram @@ -176,7 +174,7 @@ bool CGLS::iterate(unsigned int iterations) // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { // w = A*p zeroProjectionData(D_w, dims); diff --git a/cuda/3d/sirt3d.cu b/cuda/3d/sirt3d.cu index 332589e..869b2fd 100644 --- a/cuda/3d/sirt3d.cu +++ b/cuda/3d/sirt3d.cu @@ -235,8 +235,6 @@ bool SIRT::setBuffers(cudaPitchedPtr& _D_volumeData, bool SIRT::iterate(unsigned int iterations) { - shouldAbort = false; - if (useVolumeMask || useSinogramMask) precomputeWeights(); @@ -267,7 +265,7 @@ bool SIRT::iterate(unsigned int iterations) // iteration - for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + for (unsigned int iter = 0; iter < iterations && !astra::shouldAbort(); ++iter) { // copy sinogram to projection data duplicateProjectionData(D_projData, D_sinoData, dims); diff --git a/include/astra/Algorithm.h b/include/astra/Algorithm.h index af9e41d..393baf0 100644 --- a/include/astra/Algorithm.h +++ b/include/astra/Algorithm.h @@ -93,26 +93,11 @@ public: */ virtual void setGPUIndex(int /*_iGPUIndex*/) { }; - /** Signal the algorithm it should abort soon. - * This is intended to be called from a different thread - * while the algorithm is running. There are no guarantees - * on how soon the algorithm will abort. The state of the - * algorithm object will be consistent (so it is safe to delete it - * normally afterwards), but the algorithm's output is undefined. - * - * Note that specific algorithms may give guarantees on their - * state after an abort. Check their documentation for details. - */ - virtual void signalAbort() { m_bShouldAbort = true; } - protected: //< Has this class been initialized? bool m_bIsInitialized; - //< If this is set, the algorithm should try to abort as soon as possible. - volatile bool m_bShouldAbort; - private: /** * Private copy constructor to prevent CAlgorithms from being copied. diff --git a/include/astra/AsyncAlgorithm.h b/include/astra/AsyncAlgorithm.h index 0e43e67..6cb84bb 100644 --- a/include/astra/AsyncAlgorithm.h +++ b/include/astra/AsyncAlgorithm.h @@ -80,10 +80,6 @@ public: */ bool isDone() const { return m_bDone; } - /** Signal abort to the wrapped algorithm. - */ - void signalAbort(); - protected: //< Has this class been initialized? bool m_bInitialized; diff --git a/include/astra/CudaCglsAlgorithm3D.h b/include/astra/CudaCglsAlgorithm3D.h index 6f35192..63f028a 100644 --- a/include/astra/CudaCglsAlgorithm3D.h +++ b/include/astra/CudaCglsAlgorithm3D.h @@ -141,9 +141,6 @@ public: */ void setGPUIndex(int _iGPUIndex) { m_iGPUIndex = _iGPUIndex; } - - virtual void signalAbort(); - /** Get the norm of the residual image. * Only a few algorithms support this method. * diff --git a/include/astra/CudaReconstructionAlgorithm2D.h b/include/astra/CudaReconstructionAlgorithm2D.h index 197f984..56f3b25 100644 --- a/include/astra/CudaReconstructionAlgorithm2D.h +++ b/include/astra/CudaReconstructionAlgorithm2D.h @@ -122,8 +122,6 @@ public: */ virtual void run(int _iNrIterations = 0); - virtual void signalAbort(); - protected: /** Check this object. diff --git a/include/astra/CudaSirtAlgorithm3D.h b/include/astra/CudaSirtAlgorithm3D.h index 9c041b9..dd3f749 100644 --- a/include/astra/CudaSirtAlgorithm3D.h +++ b/include/astra/CudaSirtAlgorithm3D.h @@ -155,9 +155,6 @@ public: */ void setGPUIndex(int _iGPUIndex) { m_iGPUIndex = _iGPUIndex; } - - virtual void signalAbort(); - /** Get the norm of the residual image. * Only a few algorithms support this method. * diff --git a/include/astra/Globals.h b/include/astra/Globals.h index 993e443..a353940 100644 --- a/include/astra/Globals.h +++ b/include/astra/Globals.h @@ -150,6 +150,25 @@ namespace astra { }; } +//---------------------------------------------------------------------------------------- +// functions for internal use + +namespace astra { + +/** Specify a function) to be called by shouldAbort() to check if an external + * abort signal has arrived, or NULL to disable. Intended to be used by the + * matlab/python interfaces to check if Ctrl-C has been pressed. + */ +void setShouldAbortHook(bool (*pShouldAbortHook)(void)); + +/** Check if we should abort execution (due to an external signal). + */ +bool shouldAbort(); +} + +//---------------------------------------------------------------------------------------- +// functions for external use + namespace astra { _AstraExport inline int getVersion() { return ASTRA_TOOLBOXVERSION; } _AstraExport inline const char* getVersionString() { return ASTRA_TOOLBOXVERSION_STRING; } diff --git a/include/astra/cuda/2d/algo.h b/include/astra/cuda/2d/algo.h index 2ce929c..3fccdef 100644 --- a/include/astra/cuda/2d/algo.h +++ b/include/astra/cuda/2d/algo.h @@ -56,8 +56,6 @@ public: bool setSuperSampling(int raysPerDet, int raysPerPixelDim); - void signalAbort() { shouldAbort = true; } - virtual bool enableVolumeMask(); virtual bool enableSinogramMask(); @@ -137,8 +135,6 @@ protected: SFanProjection* fanProjs; float fOutputScale; - volatile bool shouldAbort; - bool freeGPUMemory; // Input/output diff --git a/include/astra/cuda/3d/algo3d.h b/include/astra/cuda/3d/algo3d.h index f5fd207..b6b1db7 100644 --- a/include/astra/cuda/3d/algo3d.h +++ b/include/astra/cuda/3d/algo3d.h @@ -41,8 +41,6 @@ public: bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs, const SProjectorParams3D& params); bool setPar3DGeometry(const SDimensions3D& dims, const SPar3DProjection* projs, const SProjectorParams3D& params); - void signalAbort() { shouldAbort = true; } - protected: void reset(); @@ -59,9 +57,6 @@ protected: SPar3DProjection* par3DProjs; float fOutputScale; - - volatile bool shouldAbort; - }; diff --git a/include/astra/cuda/3d/astra3d.h b/include/astra/cuda/3d/astra3d.h index 28a8f01..a97efd6 100644 --- a/include/astra/cuda/3d/astra3d.h +++ b/include/astra/cuda/3d/astra3d.h @@ -157,10 +157,6 @@ public: // It can be called after iterate(). float computeDiffNorm(); - // Signal the algorithm that it should abort after the current iteration. - // This is intended to be called from another thread. - void signalAbort(); - protected: AstraSIRT3d_internal *pData; }; @@ -274,10 +270,6 @@ public: // It can be called after iterate(). float computeDiffNorm(); - // Signal the algorithm that it should abort after the current iteration. - // This is intended to be called from another thread. - void signalAbort(); - protected: AstraCGLS3d_internal *pData; }; diff --git a/matlab/mex/astra_mex_algorithm_c.cpp b/matlab/mex/astra_mex_algorithm_c.cpp index 7804eeb..69ebd45 100644 --- a/matlab/mex/astra_mex_algorithm_c.cpp +++ b/matlab/mex/astra_mex_algorithm_c.cpp @@ -105,52 +105,9 @@ void astra_mex_algorithm_create(int nlhs, mxArray* plhs[], int nrhs, const mxArr } #ifdef USE_MATLAB_UNDOCUMENTED - -#ifndef USE_PTHREADS_CTRLC - -// boost version -void waitForInterrupt_boost(CAlgorithm* _pAlg) -{ - boost::posix_time::milliseconds rel(2000); - - while (!utIsInterruptPending()) { - - // This is an interruption point. If the main thread calls - // interrupt(), this thread will terminate here. - boost::this_thread::sleep(rel); - } - - //mexPrintf("Aborting. Please wait.\n"); - - // One last quick check to see if the algorithm already finished - boost::this_thread::interruption_point(); - - _pAlg->signalAbort(); -} - -#else - -// pthreads version -void *waitForInterrupt_pthreads(void *threadid) -{ - CAlgorithm* _pAlg = (CAlgorithm*)threadid; - - while (!utIsInterruptPending()) { - usleep(50000); - pthread_testcancel(); - } - - //mexPrintf("Aborting. Please wait.\n"); - - // One last quick check to see if the algorithm already finished - pthread_testcancel(); - - _pAlg->signalAbort(); - - return 0; +bool checkMatlabInterrupt() { + return utIsInterruptPending(); } - -#endif #endif //----------------------------------------------------------------------------------------- @@ -185,34 +142,12 @@ void astra_mex_algorithm_run(int nlhs, mxArray* plhs[], int nrhs, const mxArray* } // step3: perform actions -#ifndef USE_MATLAB_UNDOCUMENTED - - pAlg->run(iIterations); - -#elif defined(USE_PTHREADS_CTRLC) - - // Start a new thread to watch if the user pressed Ctrl-C - pthread_t thread; - pthread_create(&thread, 0, waitForInterrupt_pthreads, (void*)pAlg); - - pAlg->run(iIterations); - - // kill the watcher thread in case it's still running - pthread_cancel(thread); - pthread_join(thread, 0); -#else - - // Start a new thread to watch if the user pressed Ctrl-C - boost::thread interruptThread(waitForInterrupt_boost, pAlg); +#ifdef USE_MATLAB_UNDOCUMENTED + setShouldAbortHook(&checkMatlabInterrupt); +#endif pAlg->run(iIterations); - - // kill the watcher thread in case it's still running - interruptThread.interrupt(); - interruptThread.join(); - -#endif } //----------------------------------------------------------------------------------------- /** astra_mex_algorithm('get_res_norm', id); diff --git a/src/Algorithm.cpp b/src/Algorithm.cpp index f6514fc..41da987 100644 --- a/src/Algorithm.cpp +++ b/src/Algorithm.cpp @@ -33,7 +33,7 @@ namespace astra { //---------------------------------------------------------------------------------------- // Constructor -CAlgorithm::CAlgorithm() : m_bShouldAbort(false), configCheckData(0) { +CAlgorithm::CAlgorithm() : configCheckData(0) { } @@ -60,4 +60,5 @@ boost::any CAlgorithm::getInformation(std::string _sIdentifier) return std::string("not found"); } + } // namespace astra diff --git a/src/AsyncAlgorithm.cpp b/src/AsyncAlgorithm.cpp index 82f23ec..7b82376 100644 --- a/src/AsyncAlgorithm.cpp +++ b/src/AsyncAlgorithm.cpp @@ -161,10 +161,4 @@ void CAsyncAlgorithm::runWrapped(int _iNrIterations) m_bDone = true; } -void CAsyncAlgorithm::signalAbort() -{ - if (m_pAlg) - m_pAlg->signalAbort(); -} - } diff --git a/src/BackProjectionAlgorithm.cpp b/src/BackProjectionAlgorithm.cpp index 2e35bdd..97bdb33 100644 --- a/src/BackProjectionAlgorithm.cpp +++ b/src/BackProjectionAlgorithm.cpp @@ -167,8 +167,6 @@ void CBackProjectionAlgorithm::run(int _iNrIterations) // check initialized ASTRA_ASSERT(m_bIsInitialized); - m_bShouldAbort = false; - CDataProjectorInterface* pBackProjector; pBackProjector = dispatchDataProjector( diff --git a/src/CudaCglsAlgorithm3D.cpp b/src/CudaCglsAlgorithm3D.cpp index 686c5b1..2977c80 100644 --- a/src/CudaCglsAlgorithm3D.cpp +++ b/src/CudaCglsAlgorithm3D.cpp @@ -274,13 +274,6 @@ void CCudaCglsAlgorithm3D::run(int _iNrIterations) } //---------------------------------------------------------------------------------------- -void CCudaCglsAlgorithm3D::signalAbort() -{ - if (m_bIsInitialized && m_pCgls) { - m_pCgls->signalAbort(); - } -} - bool CCudaCglsAlgorithm3D::getResidualNorm(float32& _fNorm) { if (!m_bIsInitialized || !m_pCgls) diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp index d584fc8..1e81390 100644 --- a/src/CudaReconstructionAlgorithm2D.cpp +++ b/src/CudaReconstructionAlgorithm2D.cpp @@ -341,13 +341,6 @@ void CCudaReconstructionAlgorithm2D::run(int _iNrIterations) ASTRA_ASSERT(ok); } -void CCudaReconstructionAlgorithm2D::signalAbort() -{ - if (m_bIsInitialized && m_pAlgo) { - m_pAlgo->signalAbort(); - } -} - bool CCudaReconstructionAlgorithm2D::getResidualNorm(float32& _fNorm) { if (!m_bIsInitialized || !m_pAlgo) diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp index 2483704..17fea67 100644 --- a/src/CudaSirtAlgorithm3D.cpp +++ b/src/CudaSirtAlgorithm3D.cpp @@ -275,13 +275,6 @@ void CCudaSirtAlgorithm3D::run(int _iNrIterations) } //---------------------------------------------------------------------------------------- -void CCudaSirtAlgorithm3D::signalAbort() -{ - if (m_bIsInitialized && m_pSirt) { - m_pSirt->signalAbort(); - } -} - bool CCudaSirtAlgorithm3D::getResidualNorm(float32& _fNorm) { if (!m_bIsInitialized || !m_pSirt) diff --git a/src/Globals.cpp b/src/Globals.cpp index b983e3c..5f32482 100644 --- a/src/Globals.cpp +++ b/src/Globals.cpp @@ -40,5 +40,19 @@ _AstraExport bool cudaAvailable() { #endif } + +static bool (*pShouldAbortHook)(void) = 0; + +void setShouldAbortHook(bool (*_pShouldAbortHook)(void)) { + pShouldAbortHook = _pShouldAbortHook; +} + +bool shouldAbort() { + if (pShouldAbortHook && (*pShouldAbortHook)()) + return true; + + return false; +} + } diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp index 94460ba..7a3947d 100644 --- a/src/SartAlgorithm.cpp +++ b/src/SartAlgorithm.cpp @@ -288,8 +288,6 @@ void CSartAlgorithm::run(int _iNrIterations) // check initialized ASTRA_ASSERT(m_bIsInitialized); - m_bShouldAbort = false; - // data projectors CDataProjectorInterface* pFirstForwardProjector; CDataProjectorInterface* pForwardProjector; @@ -334,7 +332,7 @@ void CSartAlgorithm::run(int _iNrIterations) // iteration loop - for (int iIteration = 0; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + for (int iIteration = 0; iIteration < _iNrIterations && !shouldAbort(); ++iIteration) { int iProjection = m_piProjectionOrder[m_iIterationCount % m_iProjectionCount]; diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp index 3ea0a24..f08e8b2 100644 --- a/src/SirtAlgorithm.cpp +++ b/src/SirtAlgorithm.cpp @@ -199,8 +199,6 @@ void CSirtAlgorithm::run(int _iNrIterations) // check initialized ASTRA_ASSERT(m_bIsInitialized); - m_bShouldAbort = false; - int iIteration = 0; // data projectors @@ -290,7 +288,7 @@ void CSirtAlgorithm::run(int _iNrIterations) // iteration loop - for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + for (; iIteration < _iNrIterations && !shouldAbort(); ++iIteration) { // forward projection and difference calculation pForwardProjector->project(); |